aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--AUTHORS21
-rw-r--r--COPYRIGHT273
-rw-r--r--NEWS137
-rw-r--r--README8
-rw-r--r--audio/adlib.cpp1
-rw-r--r--audio/decoders/3do.cpp1
-rw-r--r--audio/decoders/3do.h9
-rw-r--r--audio/decoders/adpcm.cpp7
-rw-r--r--audio/decoders/adpcm.h4
-rw-r--r--audio/decoders/adpcm_intern.h6
-rw-r--r--audio/decoders/aiff.cpp8
-rw-r--r--audio/decoders/vorbis.h1
-rw-r--r--audio/decoders/wave.cpp2
-rw-r--r--audio/decoders/wave.h6
-rw-r--r--audio/miles_adlib.cpp1
-rw-r--r--audio/mods/maxtrax.cpp2
-rw-r--r--audio/mods/protracker.cpp2
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_audio.h4
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp4
-rw-r--r--audio/softsynth/mt32.cpp18
-rw-r--r--backends/audiocd/audiocd-stream.cpp199
-rw-r--r--backends/audiocd/audiocd-stream.h108
-rw-r--r--backends/audiocd/audiocd.h77
-rw-r--r--backends/audiocd/default/default-audiocd.cpp93
-rw-r--r--backends/audiocd/default/default-audiocd.h45
-rw-r--r--backends/audiocd/linux/linux-audiocd.cpp471
-rw-r--r--backends/audiocd/linux/linux-audiocd.h62
-rw-r--r--backends/audiocd/macosx/macosx-audiocd.cpp306
-rw-r--r--backends/audiocd/macosx/macosx-audiocd.h61
-rw-r--r--backends/audiocd/sdl/sdl-audiocd.cpp63
-rw-r--r--backends/audiocd/sdl/sdl-audiocd.h11
-rw-r--r--backends/audiocd/win32/msvc/ntddcdrm.h362
-rw-r--r--backends/audiocd/win32/win32-audiocd.cpp388
-rw-r--r--backends/audiocd/win32/win32-audiocd.h60
-rw-r--r--backends/events/androidsdl/androidsdl-events.cpp84
-rw-r--r--backends/events/androidsdl/androidsdl-events.h37
-rw-r--r--backends/events/sdl/sdl-events.cpp15
-rw-r--r--backends/graphics/androidsdl/androidsdl-graphics.cpp42
-rw-r--r--backends/graphics/androidsdl/androidsdl-graphics.h34
-rw-r--r--backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp8
-rw-r--r--backends/graphics/opengl/context.cpp182
-rw-r--r--backends/graphics/opengl/debug.cpp2
-rw-r--r--backends/graphics/opengl/debug.h4
-rw-r--r--backends/graphics/opengl/framebuffer.cpp259
-rw-r--r--backends/graphics/opengl/framebuffer.h175
-rw-r--r--backends/graphics/opengl/opengl-defs.h262
-rw-r--r--backends/graphics/opengl/opengl-func.h153
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp240
-rw-r--r--backends/graphics/opengl/opengl-graphics.h70
-rw-r--r--backends/graphics/opengl/opengl-sys.h154
-rw-r--r--backends/graphics/opengl/pipelines/clut8.cpp46
-rw-r--r--backends/graphics/opengl/pipelines/clut8.h (renamed from backends/graphics/opengl/extensions.cpp)32
-rw-r--r--backends/graphics/opengl/pipelines/fixed.cpp70
-rw-r--r--backends/graphics/opengl/pipelines/fixed.h46
-rw-r--r--backends/graphics/opengl/pipelines/pipeline.cpp66
-rw-r--r--backends/graphics/opengl/pipelines/pipeline.h126
-rw-r--r--backends/graphics/opengl/pipelines/shader.cpp94
-rw-r--r--backends/graphics/opengl/pipelines/shader.h59
-rw-r--r--backends/graphics/opengl/shader.cpp335
-rw-r--r--backends/graphics/opengl/shader.h288
-rw-r--r--backends/graphics/opengl/texture.cpp547
-rw-r--r--backends/graphics/opengl/texture.h332
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.cpp136
-rw-r--r--backends/graphics/openglsdl/openglsdl-graphics.h3
-rw-r--r--backends/graphics/surfacesdl/surfacesdl-graphics.cpp6
-rw-r--r--backends/midi/windows.cpp3
-rw-r--r--backends/module.mk25
-rw-r--r--backends/platform/3ds/3ds.mk64
-rw-r--r--backends/platform/3ds/README185
-rw-r--r--backends/platform/3ds/app/banner.pngbin0 -> 19241 bytes
-rw-r--r--backends/platform/3ds/app/banner.wavbin0 -> 2212 bytes
-rw-r--r--backends/platform/3ds/app/icon.pngbin0 -> 3800 bytes
-rw-r--r--backends/platform/3ds/app/scummvm.rsf219
-rw-r--r--backends/platform/3ds/config.cpp87
-rw-r--r--backends/platform/3ds/config.h45
-rw-r--r--backends/platform/3ds/gui.cpp46
-rw-r--r--backends/platform/3ds/gui.h41
-rw-r--r--backends/platform/3ds/main.cpp54
-rw-r--r--backends/platform/3ds/module.mk18
-rw-r--r--backends/platform/3ds/options-dialog.cpp98
-rw-r--r--backends/platform/3ds/options-dialog.h70
-rw-r--r--backends/platform/3ds/osystem-audio.cpp110
-rw-r--r--backends/platform/3ds/osystem-events.cpp302
-rw-r--r--backends/platform/3ds/osystem-graphics.cpp517
-rw-r--r--backends/platform/3ds/osystem.cpp193
-rw-r--r--backends/platform/3ds/osystem.h221
-rw-r--r--backends/platform/3ds/shader.v.pica59
-rw-r--r--backends/platform/3ds/sprite.cpp144
-rw-r--r--backends/platform/3ds/sprite.h71
-rw-r--r--backends/platform/android/android.mk5
-rw-r--r--backends/platform/android/events.cpp21
-rw-r--r--backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java2
-rw-r--r--backends/platform/androidsdl/androidsdl-main.cpp42
-rw-r--r--backends/platform/androidsdl/androidsdl-sdl.cpp37
-rw-r--r--backends/platform/androidsdl/androidsdl-sdl.h38
-rw-r--r--backends/platform/androidsdl/androidsdl.mk11
-rw-r--r--backends/platform/androidsdl/module.mk13
-rw-r--r--backends/platform/dc/dc.h21
-rw-r--r--backends/platform/dc/dcmain.cpp68
-rw-r--r--backends/platform/dingux/README.GCW09
-rwxr-xr-xbackends/platform/dingux/build.gcw0.sh2
-rw-r--r--backends/platform/dingux/dingux.mk7
-rw-r--r--backends/platform/ds/arm9/source/osystem_ds.cpp2
-rw-r--r--backends/platform/ds/arm9/source/osystem_ds.h3
-rw-r--r--backends/platform/maemo/debian/changelog6
-rw-r--r--backends/platform/sdl/amigaos/amigaos-main.cpp35
-rw-r--r--backends/platform/sdl/macosx/macosx.cpp7
-rw-r--r--backends/platform/sdl/macosx/macosx.h5
-rw-r--r--backends/platform/sdl/posix/posix-main.cpp2
-rw-r--r--backends/platform/sdl/posix/posix.cpp13
-rw-r--r--backends/platform/sdl/posix/posix.h2
-rw-r--r--backends/platform/sdl/sdl-sys.h30
-rw-r--r--backends/platform/sdl/sdl.cpp19
-rw-r--r--backends/platform/sdl/sdl.h5
-rw-r--r--backends/platform/sdl/win32/win32.cpp11
-rw-r--r--backends/platform/sdl/win32/win32.h4
-rw-r--r--backends/platform/symbian/src/portdefs.h3
-rw-r--r--backends/platform/tizen/graphics.cpp5
-rw-r--r--backends/platform/tizen/graphics.h2
-rw-r--r--backends/platform/tizen/system.cpp49
-rw-r--r--backends/platform/wince/portdefs.h3
-rw-r--r--backends/saves/default/default-saves.cpp155
-rw-r--r--backends/saves/default/default-saves.h25
-rw-r--r--backends/taskbar/macosx/dockplugin/dockplugin.m125
-rw-r--r--backends/taskbar/macosx/macosx-taskbar.h1
-rw-r--r--backends/taskbar/macosx/macosx-taskbar.mm67
-rw-r--r--backends/taskbar/win32/win32-taskbar.cpp8
-rw-r--r--backends/taskbar/win32/win32-taskbar.h2
-rw-r--r--backends/updates/macosx/macosx-updates.h6
-rw-r--r--backends/updates/macosx/macosx-updates.mm75
-rw-r--r--backends/updates/win32/win32-updates.cpp132
-rw-r--r--backends/updates/win32/win32-updates.h50
-rw-r--r--base/commandLine.cpp13
-rw-r--r--base/main.cpp18
-rw-r--r--base/version.cpp2
-rw-r--r--common/algorithm.h21
-rw-r--r--common/array.h81
-rw-r--r--common/gui_options.cpp1
-rw-r--r--common/gui_options.h1
-rw-r--r--common/macresman.cpp111
-rw-r--r--common/macresman.h19
-rw-r--r--common/memstream.h5
-rw-r--r--common/module.mk5
-rw-r--r--common/platform.cpp1
-rw-r--r--common/platform.h1
-rw-r--r--common/recorderfile.cpp4
-rw-r--r--common/rect.h3
-rw-r--r--common/savefile.h45
-rw-r--r--common/scummsys.h7
-rw-r--r--common/str.cpp87
-rw-r--r--common/str.h52
-rw-r--r--common/updates.cpp68
-rw-r--r--common/updates.h42
-rwxr-xr-xconfig.guess143
-rwxr-xr-xconfig.sub38
-rwxr-xr-xconfigure538
-rwxr-xr-xdevtools/create_classicmacfonts.sh (renamed from devtools/create_wage/create_wage.sh)8
-rw-r--r--devtools/create_kyradat/create_kyradat.cpp3
-rw-r--r--devtools/create_kyradat/create_kyradat.h1
-rw-r--r--devtools/create_kyradat/games.cpp3
-rw-r--r--devtools/create_kyradat/resources.cpp3
-rw-r--r--devtools/create_kyradat/resources/lok_dos.h11
-rw-r--r--devtools/create_kyradat/resources/lok_dos_cd.h11
-rw-r--r--devtools/create_kyradat/resources/lok_dos_oldfloppy.h11
-rw-r--r--devtools/create_project/cmake.cpp324
-rw-r--r--devtools/create_project/cmake.h85
-rw-r--r--devtools/create_project/cmake/CMakeLists.txt23
-rw-r--r--devtools/create_project/create_project.cpp168
-rw-r--r--devtools/create_project/create_project.h4
-rw-r--r--devtools/create_project/module.mk1
-rw-r--r--devtools/create_project/msbuild.cpp39
-rw-r--r--devtools/create_project/msvc10/create_project.vcxproj2
-rw-r--r--devtools/create_project/msvc11/create_project.vcxproj2
-rw-r--r--devtools/create_project/msvc12/create_project.vcxproj2
-rw-r--r--devtools/create_project/msvc14/create_project.vcxproj2
-rw-r--r--devtools/create_project/msvc9/create_project.vcproj8
-rw-r--r--devtools/create_project/xcode.cpp20
-rwxr-xr-xdevtools/credits.pl22
-rwxr-xr-xdevtools/encode-macbinary.sh11
-rw-r--r--devtools/scumm-md5.txt89
-rw-r--r--devtools/skycpt/COMPACT.TXT2
-rw-r--r--devtools/skycpt/README4
-rwxr-xr-xdevtools/update-version.pl1
-rw-r--r--dists/android/AndroidManifest.xml25
-rw-r--r--dists/android/AndroidManifest.xml.in25
-rw-r--r--dists/android/res/drawable-xhdpi/leanback_icon.pngbin0 -> 25962 bytes
-rw-r--r--dists/androidsdl/scummvm/AndroidAppSettings.cfg230
-rw-r--r--dists/androidsdl/scummvm/AndroidAppSettings.cfg.in230
-rw-r--r--dists/androidsdl/scummvm/AndroidBuild.sh15
-rw-r--r--dists/androidsdl/scummvm/AndroidData/logo.pngbin0 -> 77148 bytes
-rwxr-xr-xdists/androidsdl/scummvm/DataBuild.sh9
-rw-r--r--dists/androidsdl/scummvm/banner.pngbin0 -> 25962 bytes
-rwxr-xr-xdists/androidsdl/scummvm/icon.pngbin0 -> 17263 bytes
-rw-r--r--dists/engine-data/kyra.datbin496676 -> 496555 bytes
-rw-r--r--dists/engine-data/sky.cptbin419427 -> 419427 bytes
-rw-r--r--dists/gcw0/default.gcw0.desktop1
-rwxr-xr-xdists/gcw0/scummvm.sh2
-rw-r--r--dists/macosx/DS_Storebin12292 -> 15364 bytes
-rw-r--r--dists/macosx/Info.plist4
-rw-r--r--dists/macosx/Info.plist.in4
-rw-r--r--dists/macosx/dockplugin/Info.plist26
-rw-r--r--dists/macosx/dockplugin/Info.plist.in26
-rw-r--r--dists/macosx/dsa_pub.pem36
-rw-r--r--dists/macosx/scummvm_appcast.xml42
-rw-r--r--dists/macosx/scummvm_osx_appcast.xml25
-rwxr-xr-xdists/openpandora/pnd_make.sh12
-rw-r--r--dists/scummvm.rc1
-rw-r--r--dists/scummvm.rc.in1
-rw-r--r--doc/cz/PrectiMe4
-rw-r--r--doc/de/Liesmich4
-rw-r--r--doc/de/Neues117
-rw-r--r--engines/access/access.cpp21
-rw-r--r--engines/access/access.h8
-rw-r--r--engines/access/amazon/amazon_game.cpp2
-rw-r--r--engines/access/amazon/amazon_logic.cpp28
-rw-r--r--engines/access/asurface.cpp241
-rw-r--r--engines/access/asurface.h50
-rw-r--r--engines/access/bubble_box.cpp15
-rw-r--r--engines/access/char.cpp3
-rw-r--r--engines/access/detection.cpp2
-rw-r--r--engines/access/detection_tables.h2
-rw-r--r--engines/access/events.cpp5
-rw-r--r--engines/access/events.h2
-rw-r--r--engines/access/files.cpp21
-rw-r--r--engines/access/files.h6
-rw-r--r--engines/access/font.cpp9
-rw-r--r--engines/access/font.h4
-rw-r--r--engines/access/inventory.cpp1
-rw-r--r--engines/access/room.cpp4
-rw-r--r--engines/access/screen.cpp97
-rw-r--r--engines/access/screen.h32
-rw-r--r--engines/access/sound.cpp22
-rw-r--r--engines/access/sound.h10
-rw-r--r--engines/access/video.cpp8
-rw-r--r--engines/access/video.h8
-rw-r--r--engines/access/video/movie_decoder.cpp2
-rw-r--r--engines/access/video/movie_decoder.h7
-rw-r--r--engines/adl/POTFILES1
-rw-r--r--engines/adl/adl.cpp1316
-rw-r--r--engines/adl/adl.h393
-rw-r--r--engines/adl/adl_v2.cpp539
-rw-r--r--engines/adl/adl_v2.h95
-rw-r--r--engines/adl/adl_v3.cpp259
-rw-r--r--engines/adl/adl_v3.h76
-rw-r--r--engines/adl/configure.engine3
-rw-r--r--engines/adl/console.cpp333
-rw-r--r--engines/adl/console.h65
-rw-r--r--engines/adl/detection.cpp328
-rw-r--r--engines/adl/detection.h48
-rw-r--r--engines/adl/disk.cpp460
-rw-r--r--engines/adl/disk.h188
-rw-r--r--engines/adl/display.cpp545
-rw-r--r--engines/adl/display.h109
-rw-r--r--engines/adl/graphics.cpp69
-rw-r--r--engines/adl/graphics.h76
-rw-r--r--engines/adl/graphics_v1.cpp120
-rw-r--r--engines/adl/graphics_v2.cpp304
-rw-r--r--engines/adl/hires1.cpp374
-rw-r--r--engines/adl/hires1.h134
-rw-r--r--engines/adl/hires2.cpp183
-rw-r--r--engines/adl/hires2.h66
-rw-r--r--engines/adl/hires6.cpp444
-rw-r--r--engines/adl/hires6.h92
-rw-r--r--engines/adl/module.mk28
-rw-r--r--engines/adl/speaker.cpp94
-rw-r--r--engines/adl/speaker.h (renamed from backends/graphics/opengl/extensions.h)34
-rw-r--r--engines/advancedDetector.cpp79
-rw-r--r--engines/advancedDetector.h15
-rw-r--r--engines/agi/agi.cpp9
-rw-r--r--engines/agi/agi.h8
-rw-r--r--engines/agi/detection.cpp8
-rw-r--r--engines/agi/global.cpp1
-rw-r--r--engines/agi/graphics.cpp20
-rw-r--r--engines/agi/keyboard.cpp1
-rw-r--r--engines/agi/lzw.cpp1
-rw-r--r--engines/agi/op_cmd.cpp6
-rw-r--r--engines/agi/op_test.cpp4
-rw-r--r--engines/agi/picture.cpp2
-rw-r--r--engines/agi/preagi.cpp14
-rw-r--r--engines/agi/preagi.h7
-rw-r--r--engines/agi/preagi_mickey.cpp10
-rw-r--r--engines/agi/preagi_mickey.h6
-rw-r--r--engines/agi/preagi_winnie.cpp2
-rw-r--r--engines/agi/saveload.cpp7
-rw-r--r--engines/agi/sound.cpp11
-rw-r--r--engines/agi/sound.h14
-rw-r--r--engines/agi/sound_2gs.cpp5
-rw-r--r--engines/agi/sound_2gs.h1
-rw-r--r--engines/agi/sound_midi.cpp1
-rw-r--r--engines/agi/sound_pcjr.cpp5
-rw-r--r--engines/agi/sound_sarien.cpp8
-rw-r--r--engines/agi/systemui.cpp2
-rw-r--r--engines/agi/text.cpp12
-rw-r--r--engines/agi/view.h2
-rw-r--r--engines/agos/agos.cpp1
-rw-r--r--engines/agos/agos.h6
-rw-r--r--engines/agos/animation.cpp1
-rw-r--r--engines/agos/configure.engine2
-rw-r--r--engines/agos/cursor.cpp1
-rw-r--r--engines/agos/debugger.cpp1
-rw-r--r--engines/agos/detection.cpp6
-rw-r--r--engines/agos/detection_tables.h25
-rw-r--r--engines/agos/drivers/accolade/adlib.cpp5
-rw-r--r--engines/agos/drivers/accolade/driverfile.cpp1
-rw-r--r--engines/agos/drivers/accolade/mt32.cpp1
-rw-r--r--engines/agos/event.cpp5
-rw-r--r--engines/agos/feeble.cpp1
-rw-r--r--engines/agos/icons.cpp1
-rw-r--r--engines/agos/input.cpp1
-rw-r--r--engines/agos/res.cpp1
-rw-r--r--engines/agos/res_snd.cpp3
-rw-r--r--engines/agos/saveload.cpp3
-rw-r--r--engines/agos/script.cpp2
-rw-r--r--engines/agos/script_e1.cpp1
-rw-r--r--engines/agos/script_e2.cpp1
-rw-r--r--engines/agos/script_ff.cpp2
-rw-r--r--engines/agos/script_pn.cpp1
-rw-r--r--engines/agos/script_s1.cpp2
-rw-r--r--engines/agos/script_s2.cpp1
-rw-r--r--engines/agos/script_ww.cpp1
-rw-r--r--engines/agos/string.cpp7
-rw-r--r--engines/agos/string_pn.cpp2
-rw-r--r--engines/agos/subroutine.cpp3
-rw-r--r--engines/agos/vga.cpp1
-rw-r--r--engines/agos/vga_e2.cpp1
-rw-r--r--engines/agos/vga_ff.cpp1
-rw-r--r--engines/agos/vga_s1.cpp1
-rw-r--r--engines/agos/vga_s2.cpp1
-rw-r--r--engines/avalanche/animation.cpp1
-rw-r--r--engines/avalanche/avalanche.cpp1
-rw-r--r--engines/avalanche/clock.cpp2
-rw-r--r--engines/avalanche/configure.engine2
-rw-r--r--engines/avalanche/detection.cpp2
-rw-r--r--engines/avalanche/dialogs.cpp1
-rw-r--r--engines/avalanche/ghostroom.cpp1
-rw-r--r--engines/avalanche/graphics.cpp1
-rw-r--r--engines/avalanche/highscore.cpp1
-rw-r--r--engines/avalanche/mainmenu.cpp2
-rw-r--r--engines/avalanche/nim.cpp2
-rw-r--r--engines/avalanche/parser.cpp1
-rw-r--r--engines/avalanche/shootemup.cpp1
-rw-r--r--engines/avalanche/sound.cpp2
-rw-r--r--engines/avalanche/sound.h5
-rw-r--r--engines/bbvs/bbvs.cpp34
-rw-r--r--engines/bbvs/bbvs.h1
-rw-r--r--engines/bbvs/detection.cpp2
-rw-r--r--engines/bbvs/dialogs.cpp11
-rw-r--r--engines/bbvs/dialogs.h6
-rw-r--r--engines/bbvs/minigames/bbairguitar.cpp1
-rw-r--r--engines/bbvs/saveload.cpp6
-rw-r--r--engines/bbvs/sound.cpp1
-rw-r--r--engines/bbvs/sound.h5
-rw-r--r--engines/bbvs/spritemodule.cpp3
-rw-r--r--engines/bbvs/videoplayer.cpp2
-rw-r--r--engines/cge/cge.h4
-rw-r--r--engines/cge/detection.cpp4
-rw-r--r--engines/cge/events.cpp2
-rw-r--r--engines/cge/sound.cpp4
-rw-r--r--engines/cge/sound.h9
-rw-r--r--engines/cge2/cge2.h6
-rw-r--r--engines/cge2/detection.cpp4
-rw-r--r--engines/cge2/events.cpp2
-rw-r--r--engines/cge2/saveload.cpp4
-rw-r--r--engines/cge2/sound.cpp5
-rw-r--r--engines/cge2/sound.h12
-rw-r--r--engines/cge2/vga13h.cpp5
-rw-r--r--engines/cine/cine.h4
-rw-r--r--engines/cine/detection.cpp8
-rw-r--r--engines/cine/main_loop.cpp2
-rw-r--r--engines/cine/saveload.cpp5
-rw-r--r--engines/cine/script_fw.cpp4
-rw-r--r--engines/cine/sound.cpp4
-rw-r--r--engines/composer/composer.cpp7
-rw-r--r--engines/composer/composer.h5
-rw-r--r--engines/composer/configure.engine2
-rw-r--r--engines/composer/detection.cpp51
-rw-r--r--engines/cruise/cell.cpp9
-rw-r--r--engines/cruise/ctp.cpp2
-rw-r--r--engines/cruise/dataLoader.cpp11
-rw-r--r--engines/cruise/detection.cpp6
-rw-r--r--engines/cruise/sound.cpp7
-rw-r--r--engines/dialogs.cpp10
-rw-r--r--engines/draci/detection.cpp2
-rw-r--r--engines/draci/draci.h6
-rw-r--r--engines/draci/music.cpp2
-rw-r--r--engines/drascula/actors.cpp4
-rw-r--r--engines/drascula/animation.cpp22
-rw-r--r--engines/drascula/detection.cpp4
-rw-r--r--engines/drascula/drascula.cpp23
-rw-r--r--engines/drascula/drascula.h8
-rw-r--r--engines/drascula/graphics.cpp114
-rw-r--r--engines/drascula/objects.cpp4
-rw-r--r--engines/drascula/rooms.cpp12
-rw-r--r--engines/drascula/saveload.cpp28
-rw-r--r--engines/drascula/sound.cpp10
-rw-r--r--engines/drascula/talk.cpp2
-rw-r--r--engines/dreamweb/detection.cpp5
-rw-r--r--engines/dreamweb/detection_tables.h20
-rw-r--r--engines/dreamweb/dreamweb.h13
-rw-r--r--engines/dreamweb/saveload.cpp1
-rw-r--r--engines/dreamweb/sound.cpp2
-rw-r--r--engines/dreamweb/stubs.cpp1
-rw-r--r--engines/dreamweb/vgagrafx.cpp1
-rw-r--r--engines/engine.cpp9
-rw-r--r--engines/fullpipe/behavior.cpp116
-rw-r--r--engines/fullpipe/behavior.h24
-rw-r--r--engines/fullpipe/configure.engine2
-rw-r--r--engines/fullpipe/detection.cpp4
-rw-r--r--engines/fullpipe/fullpipe.cpp4
-rw-r--r--engines/fullpipe/fullpipe.h8
-rw-r--r--engines/fullpipe/gameloader.cpp12
-rw-r--r--engines/fullpipe/messagehandlers.cpp6
-rw-r--r--engines/fullpipe/motion.cpp190
-rw-r--r--engines/fullpipe/motion.h14
-rw-r--r--engines/fullpipe/scenes.h8
-rw-r--r--engines/fullpipe/scenes/scene06.cpp4
-rw-r--r--engines/fullpipe/scenes/scene07.cpp4
-rw-r--r--engines/fullpipe/scenes/scene13.cpp16
-rw-r--r--engines/fullpipe/scenes/scene14.cpp8
-rw-r--r--engines/fullpipe/sound.cpp22
-rw-r--r--engines/fullpipe/sound.h8
-rw-r--r--engines/fullpipe/statics.cpp3
-rw-r--r--engines/game.cpp6
-rw-r--r--engines/game.h4
-rw-r--r--engines/gnap/character.cpp1405
-rw-r--r--engines/gnap/character.h146
-rw-r--r--engines/gnap/configure.engine3
-rw-r--r--engines/gnap/datarchive.cpp123
-rw-r--r--engines/gnap/datarchive.h80
-rw-r--r--engines/gnap/debugger.cpp (renamed from engines/sci/graphics/paint.cpp)26
-rw-r--r--engines/gnap/debugger.h54
-rw-r--r--engines/gnap/detection.cpp196
-rw-r--r--engines/gnap/fontdata.h851
-rw-r--r--engines/gnap/gamesys.cpp1276
-rw-r--r--engines/gnap/gamesys.h213
-rw-r--r--engines/gnap/gnap.cpp1239
-rw-r--r--engines/gnap/gnap.h475
-rw-r--r--engines/gnap/grid.cpp995
-rw-r--r--engines/gnap/menu.cpp888
-rw-r--r--engines/gnap/module.mk32
-rw-r--r--engines/gnap/music.cpp104
-rw-r--r--engines/gnap/music.h50
-rw-r--r--engines/gnap/resource.cpp125
-rw-r--r--engines/gnap/resource.h190
-rw-r--r--engines/gnap/scenes/arcade.cpp2729
-rw-r--r--engines/gnap/scenes/arcade.h288
-rw-r--r--engines/gnap/scenes/group0.cpp3570
-rw-r--r--engines/gnap/scenes/group0.h401
-rw-r--r--engines/gnap/scenes/group1.cpp4501
-rw-r--r--engines/gnap/scenes/group1.h454
-rw-r--r--engines/gnap/scenes/group2.cpp3424
-rw-r--r--engines/gnap/scenes/group2.h407
-rw-r--r--engines/gnap/scenes/group3.cpp1612
-rw-r--r--engines/gnap/scenes/group3.h240
-rw-r--r--engines/gnap/scenes/group4.cpp2799
-rw-r--r--engines/gnap/scenes/group4.h298
-rw-r--r--engines/gnap/scenes/group5.cpp381
-rw-r--r--engines/gnap/scenes/group5.h77
-rw-r--r--engines/gnap/scenes/groupcs.cpp430
-rw-r--r--engines/gnap/scenes/groupcs.h122
-rw-r--r--engines/gnap/scenes/intro.cpp184
-rw-r--r--engines/gnap/scenes/intro.h47
-rw-r--r--engines/gnap/scenes/scenecore.cpp740
-rw-r--r--engines/gnap/scenes/scenecore.h70
-rw-r--r--engines/gnap/sound.cpp102
-rw-r--r--engines/gnap/sound.h57
-rw-r--r--engines/gob/detection/detection.cpp10
-rw-r--r--engines/gob/detection/tables_fascin.h14
-rw-r--r--engines/gob/detection/tables_playtoons.h18
-rw-r--r--engines/gob/gob.cpp22
-rw-r--r--engines/gob/inter_playtoons.cpp1
-rw-r--r--engines/gob/inter_v2.cpp3
-rw-r--r--engines/gob/inter_v4.cpp2
-rw-r--r--engines/gob/pregob/onceupon/onceupon.cpp2
-rw-r--r--engines/gob/pregob/pregob.h4
-rw-r--r--engines/gob/sound/adlib.h1
-rw-r--r--engines/gob/sound/bgatmosphere.cpp9
-rw-r--r--engines/gob/sound/bgatmosphere.h15
-rw-r--r--engines/gob/sound/pcspeaker.cpp1
-rw-r--r--engines/gob/sound/pcspeaker.h5
-rw-r--r--engines/gob/sound/protracker.cpp1
-rw-r--r--engines/gob/sound/protracker.h5
-rw-r--r--engines/gob/sound/sound.cpp3
-rw-r--r--engines/gob/sound/sound.h10
-rw-r--r--engines/gob/sound/soundblaster.h5
-rw-r--r--engines/gob/sound/sounddesc.cpp1
-rw-r--r--engines/gob/videoplayer.cpp2
-rw-r--r--engines/gob/videoplayer.h5
-rw-r--r--engines/groovie/cell.cpp1
-rw-r--r--engines/groovie/configure.engine2
-rw-r--r--engines/groovie/cursor.cpp2
-rw-r--r--engines/groovie/detection.cpp4
-rw-r--r--engines/groovie/font.h2
-rw-r--r--engines/groovie/graphics.cpp2
-rw-r--r--engines/groovie/groovie.cpp9
-rw-r--r--engines/groovie/groovie.h6
-rw-r--r--engines/groovie/music.cpp5
-rw-r--r--engines/groovie/music.h4
-rw-r--r--engines/groovie/player.cpp4
-rw-r--r--engines/groovie/player.h5
-rw-r--r--engines/groovie/roq.cpp1
-rw-r--r--engines/groovie/script.cpp1
-rw-r--r--engines/groovie/vdx.cpp1
-rw-r--r--engines/hopkins/configure.engine2
-rw-r--r--engines/hopkins/detection.cpp2
-rw-r--r--engines/hopkins/hopkins.h1
-rw-r--r--engines/hopkins/sound.cpp2
-rw-r--r--engines/hopkins/sound.h10
-rw-r--r--engines/hugo/detection.cpp2
-rw-r--r--engines/hugo/dialogs.cpp3
-rw-r--r--engines/hugo/dialogs.h2
-rw-r--r--engines/hugo/display.cpp1
-rw-r--r--engines/hugo/display.h5
-rw-r--r--engines/hugo/file.h2
-rw-r--r--engines/hugo/hugo.cpp3
-rw-r--r--engines/hugo/hugo.h13
-rw-r--r--engines/hugo/intro.cpp4
-rw-r--r--engines/hugo/intro.h1
-rw-r--r--engines/hugo/mouse.cpp1
-rw-r--r--engines/hugo/mouse.h7
-rw-r--r--engines/hugo/parser.cpp2
-rw-r--r--engines/hugo/parser.h1
-rw-r--r--engines/hugo/sound.cpp1
-rw-r--r--engines/hugo/sound.h5
-rw-r--r--engines/hugo/text.cpp1
-rw-r--r--engines/hugo/util.cpp6
-rw-r--r--engines/kyra/debugger.cpp2
-rw-r--r--engines/kyra/eobcommon.cpp6
-rw-r--r--engines/kyra/items_lok.cpp2
-rw-r--r--engines/kyra/kyra_lok.cpp2
-rw-r--r--engines/kyra/kyra_v2.cpp2
-rw-r--r--engines/kyra/lol.h1
-rw-r--r--engines/kyra/resource.h1
-rw-r--r--engines/kyra/sound_adlib.cpp6
-rw-r--r--engines/kyra/sound_lol.cpp10
-rw-r--r--engines/kyra/sound_towns.cpp27
-rw-r--r--engines/kyra/staticres.cpp14
-rw-r--r--engines/kyra/staticres_lol.cpp2
-rw-r--r--engines/lab/anim.cpp10
-rw-r--r--engines/lab/detection.cpp25
-rw-r--r--engines/lab/dispman.cpp1
-rw-r--r--engines/lab/engine.cpp1
-rw-r--r--engines/lab/intro.cpp2
-rw-r--r--engines/lab/lab.cpp1
-rw-r--r--engines/lab/map.cpp2
-rw-r--r--engines/lab/music.cpp2
-rw-r--r--engines/lab/music.h6
-rw-r--r--engines/lab/processroom.cpp15
-rw-r--r--engines/lab/resource.cpp2
-rw-r--r--engines/lab/special.cpp2
-rw-r--r--engines/lastexpress/configure.engine2
-rw-r--r--engines/lastexpress/detection.cpp4
-rw-r--r--engines/lastexpress/entities/gendarmes.cpp2
-rw-r--r--engines/lastexpress/lastexpress.h6
-rw-r--r--engines/lastexpress/sound/entry.cpp2
-rw-r--r--engines/lure/detection.cpp4
-rw-r--r--engines/lure/game.cpp16
-rw-r--r--engines/lure/hotspots.cpp20
-rw-r--r--engines/lure/lure.h5
-rw-r--r--engines/lure/scripts.cpp6
-rw-r--r--engines/made/database.cpp1
-rw-r--r--engines/made/detection.cpp2
-rw-r--r--engines/made/made.cpp21
-rw-r--r--engines/made/pmvplayer.cpp5
-rw-r--r--engines/made/redreader.cpp2
-rw-r--r--engines/made/resource.cpp4
-rw-r--r--engines/made/screen.cpp2
-rw-r--r--engines/made/sound.cpp5
-rw-r--r--engines/mads/debugger.cpp2
-rw-r--r--engines/mads/detection.cpp2
-rw-r--r--engines/mads/dialogs.cpp50
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.cpp6
-rw-r--r--engines/mads/dragonsphere/dragonsphere_scenes.h4
-rw-r--r--engines/mads/events.cpp6
-rw-r--r--engines/mads/font.cpp23
-rw-r--r--engines/mads/font.h2
-rw-r--r--engines/mads/game.cpp5
-rw-r--r--engines/mads/mads.cpp5
-rw-r--r--engines/mads/mads.h2
-rw-r--r--engines/mads/menu_views.cpp30
-rw-r--r--engines/mads/menu_views.h8
-rw-r--r--engines/mads/messages.cpp2
-rw-r--r--engines/mads/messages.h2
-rw-r--r--engines/mads/msurface.cpp343
-rw-r--r--engines/mads/msurface.h164
-rw-r--r--engines/mads/nebular/dialogs_nebular.cpp32
-rw-r--r--engines/mads/nebular/menu_nebular.cpp4
-rw-r--r--engines/mads/nebular/nebular_scenes.cpp8
-rw-r--r--engines/mads/nebular/nebular_scenes.h4
-rw-r--r--engines/mads/nebular/nebular_scenes2.cpp2
-rw-r--r--engines/mads/nebular/nebular_scenes3.cpp18
-rw-r--r--engines/mads/nebular/sound_nebular.cpp9
-rw-r--r--engines/mads/nebular/sound_nebular.h12
-rw-r--r--engines/mads/phantom/phantom_scenes.cpp6
-rw-r--r--engines/mads/phantom/phantom_scenes.h4
-rw-r--r--engines/mads/rails.cpp2
-rw-r--r--engines/mads/scene.cpp9
-rw-r--r--engines/mads/scene_data.cpp21
-rw-r--r--engines/mads/scene_data.h12
-rw-r--r--engines/mads/screen.cpp108
-rw-r--r--engines/mads/screen.h38
-rw-r--r--engines/mads/sequence.cpp4
-rw-r--r--engines/mads/sound.cpp6
-rw-r--r--engines/mads/sound.h15
-rw-r--r--engines/mads/sprites.cpp28
-rw-r--r--engines/mads/user_interface.cpp50
-rw-r--r--engines/mads/user_interface.h4
-rw-r--r--engines/mohawk/POTFILES1
-rw-r--r--engines/mohawk/bitmap.cpp10
-rw-r--r--engines/mohawk/configure.engine4
-rw-r--r--engines/mohawk/cstime.h2
-rw-r--r--engines/mohawk/cstime_game.cpp5
-rw-r--r--engines/mohawk/cstime_ui.cpp4
-rw-r--r--engines/mohawk/cstime_view.cpp8
-rw-r--r--engines/mohawk/cursors.cpp14
-rw-r--r--engines/mohawk/cursors.h2
-rw-r--r--engines/mohawk/detection.cpp96
-rw-r--r--engines/mohawk/detection_tables.h159
-rw-r--r--engines/mohawk/dialogs.cpp172
-rw-r--r--engines/mohawk/dialogs.h62
-rw-r--r--engines/mohawk/graphics.h8
-rw-r--r--engines/mohawk/mohawk.h4
-rw-r--r--engines/mohawk/myst.cpp35
-rw-r--r--engines/mohawk/myst.h2
-rw-r--r--engines/mohawk/myst_areas.cpp15
-rw-r--r--engines/mohawk/myst_areas.h2
-rw-r--r--engines/mohawk/myst_graphics.cpp81
-rw-r--r--engines/mohawk/myst_graphics.h4
-rw-r--r--engines/mohawk/myst_scripts.cpp10
-rw-r--r--engines/mohawk/myst_stacks/channelwood.cpp16
-rw-r--r--engines/mohawk/myst_stacks/credits.cpp5
-rw-r--r--engines/mohawk/myst_stacks/intro.cpp2
-rw-r--r--engines/mohawk/myst_stacks/makingof.cpp2
-rw-r--r--engines/mohawk/myst_stacks/mechanical.cpp6
-rw-r--r--engines/mohawk/myst_stacks/myst.cpp13
-rw-r--r--engines/mohawk/myst_stacks/myst.h2
-rw-r--r--engines/mohawk/myst_stacks/selenitic.cpp21
-rw-r--r--engines/mohawk/myst_stacks/selenitic.h1
-rw-r--r--engines/mohawk/myst_stacks/slides.cpp1
-rw-r--r--engines/mohawk/myst_state.cpp100
-rw-r--r--engines/mohawk/myst_state.h22
-rw-r--r--engines/mohawk/resource.h2
-rw-r--r--engines/mohawk/riven.cpp31
-rw-r--r--engines/mohawk/riven.h2
-rw-r--r--engines/mohawk/riven_graphics.cpp2
-rw-r--r--engines/mohawk/riven_saveload.cpp341
-rw-r--r--engines/mohawk/riven_saveload.h35
-rw-r--r--engines/mohawk/sound.cpp4
-rw-r--r--engines/mohawk/sound.h6
-rw-r--r--engines/mohawk/video.cpp137
-rw-r--r--engines/mohawk/video.h2
-rw-r--r--engines/mohawk/view.cpp52
-rw-r--r--engines/mohawk/view.h17
-rw-r--r--engines/mortevielle/configure.engine2
-rw-r--r--engines/mortevielle/detection.cpp2
-rw-r--r--engines/mortevielle/mortevielle.cpp1
-rw-r--r--engines/mortevielle/saveload.cpp2
-rw-r--r--engines/mortevielle/sound.cpp1
-rw-r--r--engines/mortevielle/sound.h5
-rw-r--r--engines/neverhood/configure.engine2
-rw-r--r--engines/neverhood/detection.cpp23
-rw-r--r--engines/neverhood/diskplayerscene.cpp1
-rw-r--r--engines/neverhood/diskplayerscene.h2
-rw-r--r--engines/neverhood/menumodule.cpp40
-rw-r--r--engines/neverhood/modules/module1300.cpp1
-rw-r--r--engines/neverhood/modules/module1300.h3
-rw-r--r--engines/neverhood/modules/module1300_sprites.h1
-rw-r--r--engines/neverhood/modules/module2800.cpp1
-rw-r--r--engines/neverhood/navigationscene.h1
-rw-r--r--engines/neverhood/neverhood.cpp2
-rw-r--r--engines/neverhood/neverhood.h7
-rw-r--r--engines/neverhood/scene.cpp1
-rw-r--r--engines/neverhood/scene.h2
-rw-r--r--engines/neverhood/screen.cpp1
-rw-r--r--engines/neverhood/screen.h5
-rw-r--r--engines/neverhood/smackerscene.cpp1
-rw-r--r--engines/neverhood/sound.cpp61
-rw-r--r--engines/neverhood/sound.h24
-rw-r--r--engines/parallaction/adlib.cpp9
-rw-r--r--engines/parallaction/balloons.cpp15
-rw-r--r--engines/parallaction/debug.cpp1
-rw-r--r--engines/parallaction/detection.cpp2
-rw-r--r--engines/parallaction/dialogue.cpp18
-rw-r--r--engines/parallaction/disk_br.cpp5
-rw-r--r--engines/parallaction/disk_ns.cpp2
-rw-r--r--engines/parallaction/exec.cpp2
-rw-r--r--engines/parallaction/font.cpp4
-rw-r--r--engines/parallaction/gfxbase.cpp3
-rw-r--r--engines/parallaction/graphics.cpp2
-rw-r--r--engines/parallaction/graphics.h2
-rw-r--r--engines/parallaction/gui_br.cpp6
-rw-r--r--engines/parallaction/gui_ns.cpp15
-rw-r--r--engines/parallaction/input.cpp5
-rw-r--r--engines/parallaction/objects.cpp7
-rw-r--r--engines/parallaction/parallaction.cpp4
-rw-r--r--engines/parallaction/parallaction.h4
-rw-r--r--engines/parallaction/parallaction_br.cpp2
-rw-r--r--engines/parallaction/parallaction_ns.cpp6
-rw-r--r--engines/parallaction/parser.cpp1
-rw-r--r--engines/parallaction/parser.h2
-rw-r--r--engines/parallaction/saveload.cpp5
-rw-r--r--engines/parallaction/sound_br.cpp7
-rw-r--r--engines/parallaction/sound_ns.cpp7
-rw-r--r--engines/pegasus/configure.engine2
-rw-r--r--engines/pegasus/detection.cpp2
-rw-r--r--engines/pegasus/input.h2
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp8
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp2
-rw-r--r--engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp1
-rw-r--r--engines/pegasus/neighborhood/mars/mars.cpp10
-rw-r--r--engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp1
-rw-r--r--engines/pegasus/neighborhood/norad/delta/globegame.cpp3
-rw-r--r--engines/pegasus/neighborhood/norad/pressuretracker.cpp1
-rw-r--r--engines/pegasus/neighborhood/wsc/wsc.cpp6
-rw-r--r--engines/pegasus/pegasus.h4
-rw-r--r--engines/prince/configure.engine2
-rw-r--r--engines/prince/debugger.cpp2
-rw-r--r--engines/prince/detection.cpp2
-rw-r--r--engines/prince/detection.h2
-rw-r--r--engines/prince/graphics.cpp2
-rw-r--r--engines/prince/mob.h2
-rw-r--r--engines/prince/module.mk3
-rw-r--r--engines/prince/prince.cpp45
-rw-r--r--engines/prince/prince.h6
-rw-r--r--engines/prince/saveload.cpp2
-rw-r--r--engines/prince/script.cpp7
-rw-r--r--engines/prince/sound.cpp9
-rw-r--r--engines/prince/sound.h6
-rw-r--r--engines/prince/videoplayer.cpp84
-rw-r--r--engines/queen/detection.cpp73
-rw-r--r--engines/queen/queen.h4
-rw-r--r--engines/queen/sound.cpp2
-rw-r--r--engines/queen/sound.h7
-rw-r--r--engines/saga/configure.engine4
-rw-r--r--engines/saga/detection.cpp6
-rw-r--r--engines/saga/detection_tables.h34
-rw-r--r--engines/saga/displayinfo.h18
-rw-r--r--engines/saga/interface.cpp35
-rw-r--r--engines/saga/isomap.cpp17
-rw-r--r--engines/saga/music.cpp3
-rw-r--r--engines/saga/music.h5
-rw-r--r--engines/saga/puzzle.cpp5
-rw-r--r--engines/saga/saga.cpp8
-rw-r--r--engines/saga/saga.h7
-rw-r--r--engines/saga/saveload.cpp4
-rw-r--r--engines/saga/scene.cpp27
-rw-r--r--engines/saga/shorten.cpp2
-rw-r--r--engines/saga/shorten.h9
-rw-r--r--engines/saga/sound.cpp2
-rw-r--r--engines/sci/configure.engine2
-rw-r--r--engines/sci/console.cpp164
-rw-r--r--engines/sci/console.h2
-rw-r--r--engines/sci/decompressor.cpp2
-rw-r--r--engines/sci/detection.cpp36
-rw-r--r--engines/sci/detection_tables.h617
-rw-r--r--engines/sci/engine/file.cpp261
-rw-r--r--engines/sci/engine/file.h46
-rw-r--r--engines/sci/engine/gc.cpp10
-rw-r--r--engines/sci/engine/kernel.cpp22
-rw-r--r--engines/sci/engine/kernel.h85
-rw-r--r--engines/sci/engine/kernel_tables.h334
-rw-r--r--engines/sci/engine/kevent.cpp27
-rw-r--r--engines/sci/engine/kfile.cpp159
-rw-r--r--engines/sci/engine/kgraphics.cpp41
-rw-r--r--engines/sci/engine/kgraphics32.cpp1107
-rw-r--r--engines/sci/engine/kmisc.cpp35
-rw-r--r--engines/sci/engine/kpathing.cpp14
-rw-r--r--engines/sci/engine/kscripts.cpp3
-rw-r--r--engines/sci/engine/ksound.cpp238
-rw-r--r--engines/sci/engine/kstring.cpp20
-rw-r--r--engines/sci/engine/kvideo.cpp153
-rw-r--r--engines/sci/engine/object.cpp9
-rw-r--r--engines/sci/engine/object.h3
-rw-r--r--engines/sci/engine/savegame.cpp302
-rw-r--r--engines/sci/engine/savegame.h3
-rw-r--r--engines/sci/engine/script_patches.cpp699
-rw-r--r--engines/sci/engine/scriptdebug.cpp10
-rw-r--r--engines/sci/engine/seg_manager.cpp62
-rw-r--r--engines/sci/engine/segment.cpp20
-rw-r--r--engines/sci/engine/segment.h23
-rw-r--r--engines/sci/engine/selector.cpp10
-rw-r--r--engines/sci/engine/selector.h8
-rw-r--r--engines/sci/engine/state.cpp7
-rw-r--r--engines/sci/engine/state.h7
-rw-r--r--engines/sci/engine/vm.cpp29
-rw-r--r--engines/sci/engine/vm.h14
-rw-r--r--engines/sci/engine/vm_types.cpp24
-rw-r--r--engines/sci/engine/vm_types.h4
-rw-r--r--engines/sci/engine/workarounds.cpp29
-rw-r--r--engines/sci/engine/workarounds.h3
-rw-r--r--engines/sci/event.cpp40
-rw-r--r--engines/sci/event.h18
-rw-r--r--engines/sci/graphics/cache.cpp4
-rw-r--r--engines/sci/graphics/cache.h2
-rw-r--r--engines/sci/graphics/celobj32.cpp578
-rw-r--r--engines/sci/graphics/celobj32.h65
-rw-r--r--engines/sci/graphics/compare.cpp72
-rw-r--r--engines/sci/graphics/compare.h3
-rw-r--r--engines/sci/graphics/controls32.cpp912
-rw-r--r--engines/sci/graphics/controls32.h469
-rw-r--r--engines/sci/graphics/cursor.cpp3
-rw-r--r--engines/sci/graphics/cursor.h2
-rw-r--r--engines/sci/graphics/frameout.cpp1535
-rw-r--r--engines/sci/graphics/frameout.h212
-rw-r--r--engines/sci/graphics/helpers.h39
-rw-r--r--engines/sci/graphics/lists32.h6
-rw-r--r--engines/sci/graphics/paint16.h4
-rw-r--r--engines/sci/graphics/paint32.cpp167
-rw-r--r--engines/sci/graphics/paint32.h44
-rw-r--r--engines/sci/graphics/palette.cpp88
-rw-r--r--engines/sci/graphics/palette.h31
-rw-r--r--engines/sci/graphics/palette32.cpp344
-rw-r--r--engines/sci/graphics/palette32.h182
-rw-r--r--engines/sci/graphics/plane32.cpp663
-rw-r--r--engines/sci/graphics/plane32.h242
-rw-r--r--engines/sci/graphics/remap.cpp99
-rw-r--r--engines/sci/graphics/remap.h67
-rw-r--r--engines/sci/graphics/remap32.cpp468
-rw-r--r--engines/sci/graphics/remap32.h400
-rw-r--r--engines/sci/graphics/screen_item32.cpp392
-rw-r--r--engines/sci/graphics/screen_item32.h84
-rw-r--r--engines/sci/graphics/text32.cpp969
-rw-r--r--engines/sci/graphics/text32.h391
-rw-r--r--engines/sci/graphics/video32.cpp415
-rw-r--r--engines/sci/graphics/video32.h312
-rw-r--r--engines/sci/graphics/view.cpp32
-rw-r--r--engines/sci/graphics/view.h3
-rw-r--r--engines/sci/module.mk7
-rw-r--r--engines/sci/parser/vocabulary.cpp14
-rw-r--r--engines/sci/parser/vocabulary.h2
-rw-r--r--engines/sci/resource.cpp48
-rw-r--r--engines/sci/resource.h13
-rw-r--r--engines/sci/resource_audio.cpp12
-rw-r--r--engines/sci/sci.cpp96
-rw-r--r--engines/sci/sci.h30
-rw-r--r--engines/sci/sound/audio.cpp54
-rw-r--r--engines/sci/sound/audio.h13
-rw-r--r--engines/sci/sound/audio32.cpp993
-rw-r--r--engines/sci/sound/audio32.h589
-rw-r--r--engines/sci/sound/decoders/sol.cpp273
-rw-r--r--engines/sci/sound/decoders/sol.h89
-rw-r--r--engines/sci/sound/drivers/amigamac.cpp3
-rw-r--r--engines/sci/sound/drivers/midi.cpp2
-rw-r--r--engines/sci/sound/music.cpp77
-rw-r--r--engines/sci/sound/music.h10
-rw-r--r--engines/sci/sound/soundcmd.cpp120
-rw-r--r--engines/sci/sound/sync.cpp76
-rw-r--r--engines/sci/sound/sync.h61
-rw-r--r--engines/scumm/POTFILES1
-rw-r--r--engines/scumm/actor.cpp194
-rw-r--r--engines/scumm/actor.h14
-rw-r--r--engines/scumm/boxes.cpp59
-rw-r--r--engines/scumm/charset-fontdata.cpp31
-rw-r--r--engines/scumm/configure.engine2
-rw-r--r--engines/scumm/debugger.cpp22
-rw-r--r--engines/scumm/detection.cpp22
-rw-r--r--engines/scumm/detection_tables.h2
-rw-r--r--engines/scumm/dialogs.cpp12
-rw-r--r--engines/scumm/dialogs.h6
-rw-r--r--engines/scumm/gfx.cpp5
-rw-r--r--engines/scumm/gfx.h2
-rw-r--r--engines/scumm/he/animation_he.cpp7
-rw-r--r--engines/scumm/he/animation_he.h4
-rw-r--r--engines/scumm/he/cup_player_he.cpp3
-rw-r--r--engines/scumm/he/intern_he.h42
-rw-r--r--engines/scumm/he/logic/moonbase_logic.cpp255
-rw-r--r--engines/scumm/he/logic_he.cpp2
-rw-r--r--engines/scumm/he/logic_he.h2
-rw-r--r--engines/scumm/he/moonbase/ai_defenseunit.cpp767
-rw-r--r--engines/scumm/he/moonbase/ai_defenseunit.h195
-rw-r--r--engines/scumm/he/moonbase/ai_main.cpp3067
-rw-r--r--engines/scumm/he/moonbase/ai_main.h211
-rw-r--r--engines/scumm/he/moonbase/ai_node.cpp153
-rw-r--r--engines/scumm/he/moonbase/ai_node.h103
-rw-r--r--engines/scumm/he/moonbase/ai_pattern.h162
-rw-r--r--engines/scumm/he/moonbase/ai_targetacquisition.cpp566
-rw-r--r--engines/scumm/he/moonbase/ai_targetacquisition.h152
-rw-r--r--engines/scumm/he/moonbase/ai_traveller.cpp279
-rw-r--r--engines/scumm/he/moonbase/ai_traveller.h123
-rw-r--r--engines/scumm/he/moonbase/ai_tree.cpp245
-rw-r--r--engines/scumm/he/moonbase/ai_tree.h84
-rw-r--r--engines/scumm/he/moonbase/ai_types.cpp176
-rw-r--r--engines/scumm/he/moonbase/ai_types.h97
-rw-r--r--engines/scumm/he/moonbase/ai_weapon.cpp88
-rw-r--r--engines/scumm/he/moonbase/ai_weapon.h59
-rw-r--r--engines/scumm/he/moonbase/distortion.cpp218
-rw-r--r--engines/scumm/he/moonbase/moonbase.cpp223
-rw-r--r--engines/scumm/he/moonbase/moonbase.h113
-rw-r--r--engines/scumm/he/moonbase/moonbase_fow.cpp423
-rw-r--r--engines/scumm/he/script_v100he.cpp431
-rw-r--r--engines/scumm/he/script_v70he.cpp41
-rw-r--r--engines/scumm/he/script_v72he.cpp42
-rw-r--r--engines/scumm/he/script_v90he.cpp34
-rw-r--r--engines/scumm/he/sound_he.cpp40
-rw-r--r--engines/scumm/he/sound_he.h8
-rw-r--r--engines/scumm/he/sprite_he.cpp30
-rw-r--r--engines/scumm/he/sprite_he.h8
-rw-r--r--engines/scumm/he/wiz_he.cpp335
-rw-r--r--engines/scumm/he/wiz_he.h90
-rw-r--r--engines/scumm/imuse_digi/dimuse.h6
-rw-r--r--engines/scumm/imuse_digi/dimuse_sndmgr.cpp4
-rw-r--r--engines/scumm/imuse_digi/dimuse_sndmgr.h11
-rw-r--r--engines/scumm/imuse_digi/dimuse_track.h5
-rw-r--r--engines/scumm/input.cpp4
-rw-r--r--engines/scumm/midiparser_ro.cpp2
-rw-r--r--engines/scumm/module.mk15
-rw-r--r--engines/scumm/object.cpp2
-rw-r--r--engines/scumm/players/player_ad.cpp30
-rw-r--r--engines/scumm/players/player_ad.h5
-rw-r--r--engines/scumm/players/player_apple2.h2
-rw-r--r--engines/scumm/players/player_mac.cpp1
-rw-r--r--engines/scumm/players/player_v2cms.cpp1
-rw-r--r--engines/scumm/players/player_v3m.h4
-rw-r--r--engines/scumm/players/player_v5m.h4
-rw-r--r--engines/scumm/saveload.cpp6
-rw-r--r--engines/scumm/saveload.h2
-rw-r--r--engines/scumm/scumm-md5.h5
-rw-r--r--engines/scumm/scumm.cpp90
-rw-r--r--engines/scumm/scumm.h16
-rw-r--r--engines/scumm/scumm_v0.h4
-rw-r--r--engines/scumm/scumm_v2.h2
-rw-r--r--engines/scumm/scumm_v6.h3
-rw-r--r--engines/scumm/smush/smush_mixer.cpp5
-rw-r--r--engines/scumm/smush/smush_mixer.h4
-rw-r--r--engines/scumm/smush/smush_player.cpp38
-rw-r--r--engines/scumm/smush/smush_player.h10
-rw-r--r--engines/scumm/sound.cpp40
-rw-r--r--engines/scumm/sound.h17
-rw-r--r--engines/scumm/string.cpp3
-rw-r--r--engines/scumm/vars.cpp13
-rw-r--r--engines/sherlock/animation.cpp6
-rw-r--r--engines/sherlock/debugger.cpp3
-rw-r--r--engines/sherlock/events.cpp8
-rw-r--r--engines/sherlock/fonts.cpp6
-rw-r--r--engines/sherlock/fonts.h6
-rw-r--r--engines/sherlock/image_file.cpp12
-rw-r--r--engines/sherlock/image_file.h8
-rw-r--r--engines/sherlock/module.mk2
-rw-r--r--engines/sherlock/music.cpp2
-rw-r--r--engines/sherlock/music.h5
-rw-r--r--engines/sherlock/objects.cpp8
-rw-r--r--engines/sherlock/saveload.cpp2
-rw-r--r--engines/sherlock/scalpel/3do/movie_decoder.cpp1
-rw-r--r--engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp286
-rw-r--r--engines/sherlock/scalpel/3do/scalpel_3do_screen.h76
-rw-r--r--engines/sherlock/scalpel/drivers/adlib.cpp4
-rw-r--r--engines/sherlock/scalpel/scalpel.cpp107
-rw-r--r--engines/sherlock/scalpel/scalpel_darts.cpp36
-rw-r--r--engines/sherlock/scalpel/scalpel_debugger.cpp3
-rw-r--r--engines/sherlock/scalpel/scalpel_inventory.cpp22
-rw-r--r--engines/sherlock/scalpel/scalpel_journal.cpp5
-rw-r--r--engines/sherlock/scalpel/scalpel_map.cpp43
-rw-r--r--engines/sherlock/scalpel/scalpel_scene.cpp44
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.cpp284
-rw-r--r--engines/sherlock/scalpel/scalpel_screen.h38
-rw-r--r--engines/sherlock/scalpel/scalpel_talk.cpp2
-rw-r--r--engines/sherlock/scalpel/scalpel_user_interface.cpp69
-rw-r--r--engines/sherlock/scalpel/scalpel_user_interface.h2
-rw-r--r--engines/sherlock/scalpel/tsage/logo.cpp8
-rw-r--r--engines/sherlock/scene.cpp11
-rw-r--r--engines/sherlock/screen.cpp134
-rw-r--r--engines/sherlock/screen.h46
-rw-r--r--engines/sherlock/sherlock.h10
-rw-r--r--engines/sherlock/sound.h3
-rw-r--r--engines/sherlock/surface.cpp261
-rw-r--r--engines/sherlock/surface.h157
-rw-r--r--engines/sherlock/talk.cpp10
-rw-r--r--engines/sherlock/tattoo/tattoo_darts.cpp69
-rw-r--r--engines/sherlock/tattoo/tattoo_fixed_text.h2
-rw-r--r--engines/sherlock/tattoo/tattoo_journal.cpp82
-rw-r--r--engines/sherlock/tattoo/tattoo_map.cpp32
-rw-r--r--engines/sherlock/tattoo/tattoo_people.cpp6
-rw-r--r--engines/sherlock/tattoo/tattoo_people.h3
-rw-r--r--engines/sherlock/tattoo/tattoo_scene.cpp22
-rw-r--r--engines/sherlock/tattoo/tattoo_screen.cpp38
-rw-r--r--engines/sherlock/tattoo/tattoo_screen.h (renamed from engines/sci/graphics/paint.h)25
-rw-r--r--engines/sherlock/tattoo/tattoo_user_interface.cpp16
-rw-r--r--engines/sherlock/tattoo/widget_base.cpp40
-rw-r--r--engines/sherlock/tattoo/widget_credits.cpp12
-rw-r--r--engines/sherlock/tattoo/widget_files.cpp28
-rw-r--r--engines/sherlock/tattoo/widget_foolscap.cpp4
-rw-r--r--engines/sherlock/tattoo/widget_inventory.cpp24
-rw-r--r--engines/sherlock/tattoo/widget_options.cpp32
-rw-r--r--engines/sherlock/tattoo/widget_password.cpp6
-rw-r--r--engines/sherlock/tattoo/widget_quit.cpp20
-rw-r--r--engines/sherlock/tattoo/widget_talk.cpp4
-rw-r--r--engines/sherlock/tattoo/widget_text.cpp4
-rw-r--r--engines/sherlock/tattoo/widget_tooltip.cpp4
-rw-r--r--engines/sherlock/tattoo/widget_verbs.cpp6
-rw-r--r--engines/sky/compact.cpp17
-rw-r--r--engines/sky/compact.h2
-rw-r--r--engines/sky/control.cpp39
-rw-r--r--engines/sky/control.h2
-rw-r--r--engines/sky/detection.cpp4
-rw-r--r--engines/sky/logic.cpp2
-rw-r--r--engines/sky/music/adlibchannel.cpp2
-rw-r--r--engines/sky/music/adlibchannel.h5
-rw-r--r--engines/sky/music/adlibmusic.cpp6
-rw-r--r--engines/sky/music/adlibmusic.h5
-rw-r--r--engines/sky/sky.h4
-rw-r--r--engines/sky/skydefs.h1
-rw-r--r--engines/sword1/configure.engine2
-rw-r--r--engines/sword1/detection.cpp12
-rw-r--r--engines/sword1/logic.h5
-rw-r--r--engines/sword1/resman.cpp13
-rw-r--r--engines/sword1/sound.cpp32
-rw-r--r--engines/sword1/sound.h2
-rw-r--r--engines/sword1/sword1.cpp1
-rw-r--r--engines/sword1/sword1.h6
-rw-r--r--engines/sword2/configure.engine2
-rw-r--r--engines/sword2/music.cpp3
-rw-r--r--engines/sword2/screen.cpp4
-rw-r--r--engines/sword2/sword2.h4
-rw-r--r--engines/sword25/POTFILES1
-rw-r--r--engines/sword25/configure.engine2
-rw-r--r--engines/sword25/detection.cpp19
-rw-r--r--engines/sword25/detection_tables.h5
-rw-r--r--engines/sword25/fmv/movieplayer.cpp2
-rw-r--r--engines/sword25/gfx/animationresource.cpp5
-rw-r--r--engines/sword25/gfx/fontresource.cpp5
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp1
-rw-r--r--engines/sword25/gfx/renderobject.cpp29
-rw-r--r--engines/sword25/gfx/text.cpp3
-rw-r--r--engines/sword25/package/packagemanager.cpp45
-rw-r--r--engines/sword25/package/packagemanager.h3
-rw-r--r--engines/sword25/sfx/soundengine.cpp1
-rw-r--r--engines/sword25/sfx/soundengine.h1
-rw-r--r--engines/sword25/sword25.h4
-rw-r--r--engines/teenagent/detection.cpp2
-rw-r--r--engines/teenagent/font.cpp1
-rw-r--r--engines/teenagent/music.cpp4
-rw-r--r--engines/teenagent/music.h1
-rw-r--r--engines/teenagent/objects.h4
-rw-r--r--engines/teenagent/resources.cpp1
-rw-r--r--engines/teenagent/scene.cpp27
-rw-r--r--engines/teenagent/scene.h4
-rw-r--r--engines/teenagent/teenagent.cpp11
-rw-r--r--engines/teenagent/teenagent.h15
-rw-r--r--engines/testbed/config.h2
-rw-r--r--engines/testbed/detection.cpp2
-rw-r--r--engines/testbed/midi.cpp1
-rw-r--r--engines/testbed/midi.h8
-rw-r--r--engines/testbed/sound.h1
-rw-r--r--engines/testbed/testbed.h6
-rw-r--r--engines/tinsel/bmv.cpp5
-rw-r--r--engines/tinsel/bmv.h5
-rw-r--r--engines/tinsel/detection.cpp14
-rw-r--r--engines/tinsel/dialogs.cpp30
-rw-r--r--engines/tinsel/handle.cpp2
-rw-r--r--engines/tinsel/music.cpp7
-rw-r--r--engines/tinsel/palette.cpp2
-rw-r--r--engines/tinsel/play.cpp3
-rw-r--r--engines/tinsel/saveload.cpp6
-rw-r--r--engines/tinsel/sound.cpp2
-rw-r--r--engines/tinsel/tinsel.cpp9
-rw-r--r--engines/tinsel/tinsel.h6
-rw-r--r--engines/toltecs/animation.cpp12
-rw-r--r--engines/toltecs/configure.engine2
-rw-r--r--engines/toltecs/detection.cpp2
-rw-r--r--engines/toltecs/menu.cpp10
-rw-r--r--engines/toltecs/movie.cpp3
-rw-r--r--engines/toltecs/movie.h5
-rw-r--r--engines/toltecs/resource.cpp1
-rw-r--r--engines/toltecs/segmap.cpp5
-rw-r--r--engines/toltecs/segmap.h2
-rw-r--r--engines/toltecs/sprite.cpp3
-rw-r--r--engines/toltecs/toltecs.h6
-rw-r--r--engines/tony/configure.engine2
-rw-r--r--engines/tony/font.cpp6
-rw-r--r--engines/tony/game.cpp7
-rw-r--r--engines/tony/gfxcore.cpp14
-rw-r--r--engines/tony/gfxcore.h1
-rw-r--r--engines/tony/mpal/loadmpc.cpp2
-rw-r--r--engines/tony/mpal/mpal.cpp41
-rw-r--r--engines/tony/mpal/mpalutils.cpp2
-rw-r--r--engines/tony/sound.cpp1
-rw-r--r--engines/tony/tony.cpp2
-rw-r--r--engines/tony/tony.h6
-rw-r--r--engines/toon/configure.engine2
-rw-r--r--engines/toon/detection.cpp2
-rw-r--r--engines/toon/toon.cpp14
-rw-r--r--engines/touche/configure.engine2
-rw-r--r--engines/touche/detection.cpp2
-rw-r--r--engines/touche/touche.cpp1
-rw-r--r--engines/touche/touche.h5
-rw-r--r--engines/tsage/blue_force/blueforce_dialogs.cpp7
-rw-r--r--engines/tsage/blue_force/blueforce_dialogs.h5
-rw-r--r--engines/tsage/blue_force/blueforce_logic.cpp4
-rw-r--r--engines/tsage/blue_force/blueforce_scenes1.cpp1
-rw-r--r--engines/tsage/blue_force/blueforce_scenes4.cpp1
-rw-r--r--engines/tsage/blue_force/blueforce_scenes5.cpp1
-rw-r--r--engines/tsage/blue_force/blueforce_scenes6.cpp5
-rw-r--r--engines/tsage/blue_force/blueforce_scenes8.cpp1
-rw-r--r--engines/tsage/converse.cpp2
-rw-r--r--engines/tsage/core.cpp10
-rw-r--r--engines/tsage/detection.cpp6
-rw-r--r--engines/tsage/dialogs.cpp6
-rw-r--r--engines/tsage/dialogs.h6
-rw-r--r--engines/tsage/events.cpp4
-rw-r--r--engines/tsage/globals.cpp4
-rw-r--r--engines/tsage/globals.h4
-rw-r--r--engines/tsage/graphics.cpp294
-rw-r--r--engines/tsage/graphics.h40
-rw-r--r--engines/tsage/module.mk1
-rw-r--r--engines/tsage/ringworld/ringworld_demo.cpp7
-rw-r--r--engines/tsage/ringworld/ringworld_dialogs.cpp9
-rw-r--r--engines/tsage/ringworld/ringworld_dialogs.h2
-rw-r--r--engines/tsage/ringworld/ringworld_logic.cpp2
-rw-r--r--engines/tsage/ringworld/ringworld_scenes2.cpp1
-rw-r--r--engines/tsage/ringworld/ringworld_scenes3.cpp6
-rw-r--r--engines/tsage/ringworld/ringworld_scenes5.cpp4
-rw-r--r--engines/tsage/ringworld2/ringworld2_dialogs.cpp5
-rw-r--r--engines/tsage/ringworld2/ringworld2_dialogs.h2
-rw-r--r--engines/tsage/ringworld2/ringworld2_logic.cpp35
-rw-r--r--engines/tsage/ringworld2/ringworld2_outpost.cpp3
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes0.cpp6
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes1.cpp1
-rw-r--r--engines/tsage/ringworld2/ringworld2_scenes2.cpp2
-rw-r--r--engines/tsage/saveload.cpp4
-rw-r--r--engines/tsage/scenes.cpp7
-rw-r--r--engines/tsage/screen.cpp51
-rw-r--r--engines/tsage/screen.h66
-rw-r--r--engines/tsage/sound.h5
-rw-r--r--engines/tsage/tsage.h13
-rw-r--r--engines/tsage/user_interface.cpp12
-rw-r--r--engines/tucker/detection.cpp2
-rw-r--r--engines/tucker/resource.cpp8
-rw-r--r--engines/tucker/tucker.h4
-rw-r--r--engines/voyeur/animation.cpp7
-rw-r--r--engines/voyeur/animation.h5
-rw-r--r--engines/voyeur/data.cpp16
-rw-r--r--engines/voyeur/debugger.cpp2
-rw-r--r--engines/voyeur/detection.cpp2
-rw-r--r--engines/voyeur/events.cpp58
-rw-r--r--engines/voyeur/files.cpp115
-rw-r--r--engines/voyeur/files.h12
-rw-r--r--engines/voyeur/files_threads.cpp74
-rw-r--r--engines/voyeur/module.mk2
-rw-r--r--engines/voyeur/screen.cpp (renamed from engines/voyeur/graphics.cpp)127
-rw-r--r--engines/voyeur/screen.h (renamed from engines/voyeur/graphics.h)22
-rw-r--r--engines/voyeur/sound.cpp2
-rw-r--r--engines/voyeur/sound.h2
-rw-r--r--engines/voyeur/voyeur.cpp165
-rw-r--r--engines/voyeur/voyeur.h4
-rw-r--r--engines/voyeur/voyeur_game.cpp306
-rw-r--r--engines/wage/debugger.cpp97
-rw-r--r--engines/wage/debugger.h47
-rw-r--r--engines/wage/design.cpp234
-rw-r--r--engines/wage/design.h48
-rw-r--r--engines/wage/detection.cpp10
-rw-r--r--engines/wage/detection_tables.h168
-rw-r--r--engines/wage/dialog.cpp15
-rw-r--r--engines/wage/dialog.h2
-rw-r--r--engines/wage/entities.cpp29
-rw-r--r--engines/wage/entities.h6
-rw-r--r--engines/wage/gui-console.cpp169
-rw-r--r--engines/wage/gui.cpp576
-rw-r--r--engines/wage/gui.h76
-rw-r--r--engines/wage/macmenu.cpp (renamed from engines/wage/menu.cpp)364
-rw-r--r--engines/wage/macmenu.h (renamed from engines/wage/menu.h)62
-rw-r--r--engines/wage/macwindow.cpp376
-rw-r--r--engines/wage/macwindow.h161
-rw-r--r--engines/wage/macwindowmanager.cpp379
-rw-r--r--engines/wage/macwindowmanager.h141
-rw-r--r--engines/wage/module.mk5
-rw-r--r--engines/wage/script.cpp4
-rw-r--r--engines/wage/script.h4
-rw-r--r--engines/wage/util.cpp15
-rw-r--r--engines/wage/wage.cpp52
-rw-r--r--engines/wage/wage.h20
-rw-r--r--engines/wage/world.cpp32
-rw-r--r--engines/wage/world.h6
-rw-r--r--engines/wintermute/base/base_engine.cpp2
-rw-r--r--engines/wintermute/base/base_engine.h2
-rw-r--r--engines/wintermute/base/base_persistence_manager.cpp14
-rw-r--r--engines/wintermute/base/base_persistence_manager.h4
-rw-r--r--engines/wintermute/base/file/base_disk_file.cpp27
-rw-r--r--engines/wintermute/base/sound/base_sound_manager.cpp15
-rw-r--r--engines/wintermute/configure.engine2
-rw-r--r--engines/wintermute/detection.cpp12
-rw-r--r--engines/wintermute/detection_tables.h5
-rw-r--r--engines/wintermute/ui/ui_window.cpp11
-rw-r--r--engines/wintermute/wintermute.cpp2
-rw-r--r--engines/wintermute/wintermute.h4
-rw-r--r--engines/zvision/configure.engine2
-rw-r--r--engines/zvision/core/events.cpp1
-rw-r--r--engines/zvision/detection.cpp2
-rw-r--r--engines/zvision/scripting/actions.h2
-rw-r--r--engines/zvision/sound/midi.cpp1
-rw-r--r--engines/zvision/sound/midi.h2
-rw-r--r--engines/zvision/zvision.cpp2
-rw-r--r--graphics/VectorRenderer.cpp29
-rw-r--r--graphics/VectorRenderer.h60
-rw-r--r--graphics/VectorRendererSpec.cpp1721
-rw-r--r--graphics/VectorRendererSpec.h73
-rw-r--r--graphics/font.cpp23
-rw-r--r--graphics/font.h4
-rw-r--r--graphics/managed_surface.cpp260
-rw-r--r--graphics/managed_surface.h376
-rw-r--r--graphics/module.mk3
-rw-r--r--graphics/nine_patch.cpp279
-rw-r--r--graphics/nine_patch.h98
-rw-r--r--graphics/scaler/thumbnail_intern.cpp6
-rw-r--r--graphics/screen.cpp129
-rw-r--r--graphics/screen.h118
-rw-r--r--graphics/surface.cpp105
-rw-r--r--graphics/surface.h68
-rw-r--r--graphics/transparent_surface.cpp133
-rw-r--r--graphics/transparent_surface.h8
-rw-r--r--gui/EventRecorder.cpp3
-rw-r--r--gui/ThemeEngine.cpp476
-rw-r--r--gui/ThemeEngine.h31
-rw-r--r--gui/ThemeEval.cpp16
-rw-r--r--gui/ThemeLayout.cpp2
-rw-r--r--gui/ThemeLayout.h40
-rw-r--r--gui/Tooltip.cpp2
-rw-r--r--gui/Tooltip.h3
-rw-r--r--gui/credits.h17
-rw-r--r--gui/debugger.cpp11
-rw-r--r--gui/dialog.cpp10
-rw-r--r--gui/dialog.h2
-rw-r--r--gui/gui-manager.cpp52
-rw-r--r--gui/gui-manager.h9
-rw-r--r--gui/launcher.cpp2
-rw-r--r--gui/module.mk6
-rw-r--r--gui/object.cpp13
-rw-r--r--gui/options.cpp71
-rw-r--r--gui/options.h9
-rw-r--r--gui/predictivedialog.cpp19
-rw-r--r--gui/predictivedialog.h1
-rw-r--r--gui/recorderdialog.cpp1
-rw-r--r--gui/saveload-dialog.cpp2
-rw-r--r--gui/saveload.cpp1
-rw-r--r--gui/saveload.h2
-rw-r--r--gui/themes/default.inc38
-rw-r--r--gui/themes/scummclassic.zipbin111410 -> 115643 bytes
-rw-r--r--gui/themes/scummclassic/classic_layout.stx17
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx21
-rw-r--r--gui/themes/scummmodern.zipbin1487187 -> 1491681 bytes
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx17
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx21
-rw-r--r--gui/themes/translations.datbin538061 -> 570539 bytes
-rw-r--r--gui/updates-dialog.cpp148
-rw-r--r--gui/updates-dialog.h (renamed from engines/scumm/he/logic/moonbase.cpp)44
-rw-r--r--gui/widget.cpp119
-rw-r--r--gui/widget.h19
-rw-r--r--gui/widgets/editable.cpp4
-rw-r--r--gui/widgets/edittext.cpp8
-rw-r--r--gui/widgets/list.cpp8
-rw-r--r--gui/widgets/popup.cpp29
-rw-r--r--gui/widgets/popup.h1
-rw-r--r--gui/widgets/scrollbar.cpp7
-rw-r--r--gui/widgets/scrollcontainer.cpp147
-rw-r--r--gui/widgets/scrollcontainer.h63
-rw-r--r--gui/widgets/tab.cpp24
-rw-r--r--gui/widgets/tab.h1
-rw-r--r--image/codecs/bmp_raw.cpp44
-rw-r--r--image/codecs/cinepak.cpp2
-rw-r--r--image/codecs/codec.cpp3
-rw-r--r--image/codecs/msrle4.cpp140
-rw-r--r--image/codecs/msrle4.h53
-rw-r--r--image/module.mk1
-rw-r--r--image/pict.cpp2
-rw-r--r--po/POTFILES2
-rw-r--r--po/be_BY.po862
-rw-r--r--po/ca_ES.po851
-rw-r--r--po/cs_CZ.po852
-rw-r--r--po/da_DK.po852
-rw-r--r--po/de_DE.po895
-rw-r--r--po/es_ES.po852
-rw-r--r--po/eu.po860
-rw-r--r--po/fi_FI.po851
-rw-r--r--po/fr_FR.po857
-rw-r--r--po/gl_ES.po852
-rwxr-xr-x[-rw-r--r--]po/hu_HU.po856
-rw-r--r--po/it_IT.po852
-rw-r--r--po/nb_NO.po852
-rw-r--r--po/nl_NL.po862
-rw-r--r--po/nn_NO.po852
-rw-r--r--po/pl_PL.po852
-rw-r--r--po/pt_BR.po849
-rw-r--r--po/ru_RU.po926
-rw-r--r--po/scummvm.pot840
-rw-r--r--po/sv_SE.po852
-rw-r--r--po/uk_UA.po862
-rw-r--r--po/zh-Latn_CN.po3856
-rw-r--r--ports.mk68
-rw-r--r--test/common/algorithm.h56
-rw-r--r--test/common/array.h40
-rw-r--r--test/common/str.h74
-rw-r--r--test/module.mk1
-rw-r--r--video/coktel_decoder.cpp4
-rw-r--r--video/coktel_decoder.h2
-rw-r--r--video/mpegps_decoder.cpp1
-rw-r--r--video/psx_decoder.cpp1
1296 files changed, 98810 insertions, 19979 deletions
diff --git a/.gitignore b/.gitignore
index 03e3393220..2ad104214e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ lib*.a
/config.log
/scummvm
/scummvm-static
+/ScummVMDockTilePlugin*
/config.h
/config.mk
/.gdb_history
@@ -19,6 +20,7 @@ lib*.a
/MT32_CONTROL.ROM
/MT32_PCM.ROM
/ScummVM.app
+/scummvm.docktileplugin
/scummvm-ps3.pkg
/*.ipk
/.project
@@ -164,6 +166,7 @@ ipch/
*.vcxproj*
*.bat
*.tss
+*.VC.db
#Ignore default Visual Studio build folders
[Dd]ebug/
diff --git a/AUTHORS b/AUTHORS
index eff485cdc1..59e0d70fcf 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -47,7 +47,7 @@ ScummVM Team
AGI:
Stuart George
- Matthew Hoops
+ Matthew Hoops - (retired)
Filippos Karapetis
Martin Kiewitz
Pawel Kolodziejski
@@ -104,6 +104,7 @@ ScummVM Team
Drascula:
Filippos Karapetis
Pawel Kolodziejski
+ Thierry Crozat
DreamWeb:
Torbjorn Andersson
@@ -112,6 +113,10 @@ ScummVM Team
Vladimir Menshakov - (retired)
Willem Jan Palenstijn
+ Gnap:
+ Arnaud Boutonne
+ Benjamin Haisch
+
Gob:
Torbjorn Andersson
Arnaud Boutonne
@@ -140,7 +145,7 @@ ScummVM Team
Johannes Schickel
Lastexpress:
- Matthew Hoops
+ Matthew Hoops - (retired)
Jordi Vilalta Prat
Julien Templier
@@ -158,7 +163,7 @@ ScummVM Team
Mohawk:
Bastien Bouclet
- Matthew Hoops
+ Matthew Hoops - (retired)
Filippos Karapetis
Alyssa Milburn
Eugene Sandulenko
@@ -176,7 +181,7 @@ ScummVM Team
peres
Pegasus:
- Matthew Hoops
+ Matthew Hoops - (retired)
Queen:
David Eriksson - (retired)
@@ -281,6 +286,7 @@ ScummVM Team
Android:
Andre Heider
Angus Lees
+ Lubomyr Lisen
Dreamcast:
Marcus Comstedt
@@ -302,6 +308,9 @@ ScummVM Team
Frantisek Dufka - (retired)
Tarek Soliman
+ Nintendo 3DS:
+ Thomas Edvalson
+
Nintendo 64:
Fabio Battaglia
@@ -401,7 +410,8 @@ ScummVM Team
Thierry Crozat - Numerous contributions to documentation
Joachim Eberhard - Numerous contributions to documentation
(retired)
- Matthew Hoops - Wiki editor
+ Matthew Hoops - Numerous contributions to documentation
+ (retired)
Retired Team Members
--------------------
@@ -444,6 +454,7 @@ Other contributions
Mac OS X:
Max Horn - (retired)
Oystein Eftevaag
+ Thierry Crozat
Mandriva:
Dominik Scherer - (retired)
diff --git a/COPYRIGHT b/COPYRIGHT
index a4807f936a..5ac5822799 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -4,215 +4,404 @@ Copyright (C) 2001-2016 by the following:
If you have contributed to this project then you deserve to be on this
list. Contact us (see: AUTHORS) and we'll add you.
-Tore Anderson
+Manuel Alfayate
Torbjorn Andersson
+Tore Anderson
+Matteo Angelino
Chris Apers
+Adrian Astley
+Bertrand Augereau
Ori Avtalion
Nicolas Bacca
+Dobo Balazs
+Daniel Balsom
+Yotam Barnoy
Fabio Battaglia
+Vincent Benony
+Alex Bevilacqua
+Laurent Blume
Bastien Bouclet
Arnaud Boutonne
+Francois-R Boyer
+Peter Bozso
Jurgen Braam
Ralph Brorsen
James Brown
+Henry Bush
Stuart Caie
+Rainer Canavan
+Ben Castricum
+Xiaojun Chen
Jamieson Christian
+Ryan Clark
+William Claydon
+Fabien Coeurjoly
Marcus Comstedt
+David Corrales-Lopez
Paolo Costabel
+Robert Crossfield
Thierry Crozat
+Vyacheslav Dikonov
+Paul David Doherty
+Martin Doucha
Ivan Dubrov
Frantisek Dufka
+Sylvain Dupont
+Joachim Eberhard
+Thomas Edvalson
Oystein Eftevaag
-Kovacs Endre Janos
David Eriksson
+Thomas Fach-Pedersen
+Yaroslav Fedevych
Jerome Fisher
+Hampus Flink
+Hans-Joerg Frieden
+Greg Frieger
+Tom Frost
Stuart George
Paul Gilbert
+Jean Marc Gimenez
Robert Goeffringmann
+Victor Gonzalez
+GrajPoPolsku.pl Team
+Chris Gray
Jonathan Gray
+Tobias Gunkel
Benjamin Haisch
Vincent Hamm
+Ruediger Hanke
+Matt Hargett
+Andre Heider
Sven Hesse
Jochen Hoenicke
Matthew Hoops
Max Horn
Travis Howell
Janne Huttunen
+Ravi I.
Felix Jakschitsch
+Kovacs Endre Janos
Jeroen Janssen
+Emmanuel Jeandel
+Dmitry Jemerov
+David Jensen
Florian Kagerer
+Keith Kaisershot
Filippos Karapetis
Andreas Karlsson
+Denis Kasak
+Chris Kehler
+Robert Kelsen
Ismail Khatib
Oliver Kiehl
Martin Kiewitz
Pawel Kolodziejski
+George Kormendi
Mutwin Kraus
+Stefan Kristiansson
Andrew Kurushin
+Daniel ter Laan
+Hugo Labrande
+Christopher T. Lansdown
+Sergey Lapin
Angus Lees
+Rickard Lind
+Max Lingua
+Lubomyr Lisen
+Ivan Lukyanov
+Tomas Maidagan
+Hubert Maier
+Johannes Manhave
+Lothar Serra Mari
+Vicent Marti
Claudio Matsuoka
Thomas Mayer
+Robert Megone
+Vladimir Menshakov
Alyssa Milburn
Neil Millstone
+Dark Minister
Gregory Montoir
+Peter Moraliyski
+Carl Muckenhoupt
+Alejandro Gomez de la Munoza
+Sean Murray
Kostas Nakos
Mikesch Nepomuk
+Jeremy Newman
+Anders Baden Nielsen
+Juha Niemimaki
+Walter van Niftrik
Nicolas Noble
+Steffen Nyeland
+Rune Orsval
+Chris Page
Willem Jan Palenstijn
+Stefan Parviainen
+Solomon Peachy
Lars Persson
Joost Peters
Tim Phillips
+Robey Pointer
+Jordi Vilalta Prat
+Magnus Reftel
+Christoph Reichenbach
+George Reid
+Klaus Reimer
+Andreas Roever
Edward Rudd
+Toni Saarela
+Kari Salminen
Eugene Sandulenko
+Santiago G. Sanz
+Simon Sawatzki
+Daniel Schepler
+Dominik Scherer
Johannes Schickel
+Luc Schrijvers
+Zbynik Schwarz
Keith Scroggins
+Dan Serban
+Lars Skovlund
+Paul Smedley
+Colin Snover
Tarek Soliman
+Einar Johan T. Somaaen
+Andre Souza
+Robert Spalek
+Rink Springer
Won Star
+Markus Strangl
Ludvig Strigeus
Fedor Strizhniou
David Symonds
-Jordi Vilalta
+Rainer De Temple
+Julien Templier
+Sean Terrell
+Tobia Tesan
+Scott Thomas
+David Turner
+Lionel Ulmer
+Mikel Iturbe Urretxa
+Hugues Valois
+Petr Vyhnak
+Chris Warren-Smith
Robin Watts
+Lukasz Watka
+David Weinehall
+Fredrik Wendel
John Willis
+Anton Yarcev
+Bas Zoetekouw
Jezar
n0p
peres
Quietust
+ScummBR Team
+Raina
Patches contributed by:
Laura Abbott "sageofminerva"
Vikram Aggarwal "youngelf"
-the rara avis "theraraavis"
+Norbert Bajko
+Giovanni Bajo
+Matan Bareket
Dieter Baron "dillo"
+Kevin Becker
Alban Bedel "albeu"
Bodo Bellut "bellut"
-Bramvandijk "bramvandijk"
+Nagy Bendeguz
Andreas Bierfert "awjb"
+Kaustav Biswas
Elio Blanca "eblanca76"
+Martin Bohm
David Breakey "dbreakey"
+Michael du Breuil "WickedShell"
+Michael Brown
Robert Buchholz "prendi"
-Rainer Canavan "canavan"
+Sander Buskens
+Giulio Camuffo
+Kevin Carnes
Mathieu Carot "yokna"
Stefano Ceccherini "jackburton"
Travis S Coady "theealien"
Josh Coalson "jcoalson"
+Curt Coder
Thomas Combeleran "hibernatus"
+Patrick Combet
Kees Cook "keescook"
Carlos Corbacho "cathectic"
+Andrea Corna
Roberto Costa "fiix76"
-dc france "erwan2004"
-dewt "mncl"
-Martin Doucha "next_ghost"
+Eric Culp
+Alexander Dergunov
+Alexandre Detiste
+Roman Donchenko
+Heather Douglass
Michael Drueing "doc_wagon"
-Michael du Breuil "WickedShell"
-dubsdj
Matthew Duggan "stauff1"
+Barry Duncan
Olivier Duverne "richiefs"
Andrei Dziahel "develop7"
John Eckerdal "johneck"
-Thomas Fach-Pedersen "madm00se"
-Florent "flobo"
-Florob "florob"
+Abdeselam El-Haman
+Henrik Engqvist
Mike Frysinger "vapier"
+Bence Gazder
Chris Gelatt "kreeblah"
Jens Georg "phako"
Nicolas George "cigaes"
+Martin Gerhardy
Jonathan Gevaryahu "lord_nightmare"
+Boris Gnezdilov
Tobias Gruetzmacher "tobig"
Damien Guard "damienguard"
-Tobias Gunkel "tobigun"
Matti Hamalainen "ccrtnsp"
-Matt Hargett "matt_hargett"
+Lauri Harsila
Stefan Haubenthal "polluks"
+Gavin Hayler
Alexander Holler "holler"
+Enrico Horn
Falk Hueffner "mellum"
Casey Hutchinson "nnooiissee"
-j0tt
+Tomas Jakobsson
Gregor Jasny "gjasny"
-Jellby "jellby"
-Joerg "macdrega"
Matt Johnson "mattjon"
Nicolas Joly "njoly"
-KeithS "keithscr"
+Yusuke Kamiyamane
+Martin Kennedy
+Stephen Kennedy
Sam Kenny "sam_k"
Koen Kooi "koenkooi"
+Christoph Korn
+Christian Krause
+Till Kresslein
Zygmunt Krynicki "zygoon"
Janne Kujanpaa "jukuja"
+Neeraj Kumar
+Oleksiy Kurochko
Jay Lanagan "r0ni"
Norbert Lange "nolange"
Manuel Lauss "mlau2"
Rolf Leggewie "leggewie"
+Jim Leiterman
+Matt Lewandowsky
+Chenbo Li
+Rob Loach
Duncan Lock "dflock"
Mark Lodato "itsr0y"
Fridvin Logi "phillip_j_fry"
-Lostech "lostech"
+Michael Lojkovic
+Borja Lorente Escobar
Georg Lukas "ge0rg"
+Artem Lukoyanov
Michael Madsen "pidgeot"
+Matthias Mailander
+Narek Mailian
+Christoph Mallon
+Engin Manap
Dmitry Marakasov "amdmi3"
Alejandro Marzini "vgvgf"
Connor McLeod "mcleod2032"
Mickey McMurray "metafox"
-Vladimir Menshakov "megath"
Adam Metcalf "gamblore"
+Nicola Mettifogo
Frank Meyering "frank_m24"
Gael Le Migno "kilobug"
+Etienne Millon
Andy Molloy "maloi"
-Sean Murrau "lightcast"
+Omer Mor
Armin Mueller "arm_in"
+Sean Murrau "lightcast"
Andrea Musuruane "musuruan"
KO Myung-Hun "lvzuufx"
Markus Napp "meist3r"
Peter Naulls "pnaulls"
Christian Neumair "mannythegnome"
-Nicos "anarxia"
-Juha Niemimaki "capehill"
+Hannes Niederhausen
Markus Niemisto "niemisto"
-ole
+Bastien Nocera
+Jody Northup
+Julian Ospald
+Christopher Page
Chris Paras "paras_rasmatazz"
Aubin Paul "outlyer"
+Michael Pearce
Vincent Pelletier "subdino"
-phi1
-Pix2 "pix2"
+Jussi Pitkanen
Carsten Pohl "carstenpohl"
+Tony Puccinelli
Markus Pyykko "mankeli"
-Richard "trinity78"
-Felix Riemann "kirschsaft"
+Rodrigo Rebello
+Alexander Reim
Thomas Richter "thorfdbg"
+Felix Riemann "kirschsaft"
Timo Roehling "t1m0"
-Andreas Roever "roever"
Jonathan Rogers "jonner"
+Enrico Rolfi
+Doron Rosenberg
Marek Roth "logicdeluxe"
+David Russo
Uwe Ryssel "uweryssel"
-Simon Sawatzki "simsaw"
-Scarlatti "escarlate"
-Daniel Schepler "dschepler"
Florian Schmitt "fatpenguin"
Mark Schreiber "mark7"
Ben Shadwick "benshadwick"
+Rodrigo Silva
Jean-Yves Simon "lethalwp"
Andrej Sinicyn "andrej4000"
-Andre Souza "luke_br"
-spookypeanut "spookypeanut"
+Dmitry Smirnov
Steve Stavropoulos "isnothere"
Daniel Steinberger "amorphousshape"
Sven Strothoff "dataslayer"
Andrea Suatoni "mrhandler"
-tbcarey
-Tim "tipabu"
+Max Tabachenko
+DOSBox Team
+Sarien Team
+Joel Teichroeb
+Jimmi Thogersen
+Alexander Tkachov
+Pino Toscano
Luigi Toscano "ltosky"
Xavier Trochu "xtrochu"
+Vasyl Tsvirkunov
Michal Tulacek "tutchek"
Michael Udaltsov "cccp99"
+Joni Vahamaki
Kristof Vansant "lupusbe"
+Aaryaman Vasishta
Tim Walters "realmz"
-David Weinehall "weine"
Eric A. Welsh "eweish42"
Yudhi Widyatama "yudhi97"
+Jakub Wilk
+Kieron Wilkinson
Robert Wohlrab "moshroum"
-Xanathar "xanathar"
+James Woodcock
Grant Yeager "glo_kidd"
Benjamin W. Zale "junior_aepi"
-Yotam Barnoy "bluddy"
-Tom Frost "TomFrost"
+Kamil Zbrog
+Michal Ziabkowski
+Bramvandijk "bramvandijk"
+Canadacow
+countingpine
+Damien
+dc france "erwan2004"
+dewt "mncl"
+dubsdj
+Florent "flobo"
+Florob "florob"
+j0tt
+Jellby "jellby"
+Joerg "macdrega"
+Lostech "lostech"
+Nicos "anarxia"
+ole
+phi1
+Pix2 "pix2"
+Richard "trinity78"
+Scarlatti "escarlate"
+the rara avis "theraraavis"
+Tim "tipabu"
+vandalo
+Xanathar "xanathar"
diff --git a/NEWS b/NEWS
index 7d0637a525..193141d8b7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,142 @@
For a more comprehensive changelog of the latest experimental code, see:
https://github.com/scummvm/scummvm/commits/
-1.9.0 (XXXX-XX-XX)
+1.9.0 (YYYY-MM-DD)
+ New Games:
+ - Added support for Myst.
+ - Added support for Myst: Masterpiece Edition.
+ - Added support for U.F.O.s.
+
+ General:
+ - Fixed audio corruption in the MS ADPCM decoder.
+
+ AGI:
+ - Added support for Hercules rendering. Both green and amber modes are
+ supported.
+ - Added support for the Hercules high resolution font. The font is also
+ usable outside of Hercules rendering.
+ - Added optional "pause, when entering commands" feature, that was only
+ available in the original interpreter for Hercules rendering.
+
+ Beneath a Steel Sky:
+ - Fixed a bug that could possibly make the game unfinishable due to a
+ wrong animation for Officer Blunt that makes further interaction with
+ this character impossible.
+
+ Gob:
+ - Fixed graphical issues in Gobliiins (EGA version).
+
+ SCI:
+ - Fixed a missing dialog line in QfG3 which awards the player with 3 additional
+ points. This is a bug in the original game interpreter. Due to this bug,
+ it was not possible to get all points in the original game.
+ - Fixed a bug in Space Quest 1 that caused issues with the spider droid.
+ - Fixed a bug in Laura Bow: The Colonel's Bequest that could cause a lock-up when
+ interacting with the armor in room 37 (main house, downstairs). This bug is also
+ present in the original game.
+ - Fixed auto-saving in the fan-made Cascade Quest.
+ - Fixed a bug in Conquests of the Longbow: The Adventures of Robin Hood that caused
+ the game to crash while wandering through the Sherwood Forest.
+ - Added a detection entry for the ImagiNation Network (INN) demo.
+
+ SCUMM:
+ - Fixed missing translations in the in-game quit and restart dialogs in Pajama Sam 1.
+ - Fixed visual glitches in DOTT that occured after loading a savegame with the stereo
+ in Green Tentacle's room turned on.
+ - Improved timing and pathfinding in Maniac Mansion (C64 and Apple II versions)
+
+ Mohawk:
+ - Fixed visual glitches in the Spanish version of Myst.
+ - Changed the cancel button in the options dialog of Riven not to save the settings.
+ - Riven savegames created by ScummVM are now loadable in the original game.
+
+ WAGE:
+ - Closed memory leak.
+
+ Windows port:
+ - Fixed taskbar support on Windows 10 onwards.
+
+1.8.1 (2016-05-25)
+ New ports:
+ - Added Nintendo 3DS port.
+ - Added Android SDL port.
+
+ General:
+ - Removed TESTING flag from several supported games.
+ - Added Chinese Pinyin translation.
+ - Fixed cursor stuttering in the launcher that occured on some systems.
+ BBVS:
+ - Fixed game restart.
+
+ CinE:
+ - Fixed sound effect loading.
+
+ Drascula:
+ - Fixed text alignment to be faithful to the original.
+ - Fixed character walking off screen.
+ - Fixed loading savegames in the Pendulum scene.
+ - Fixed wrong background for inventory items during chapter 6 in the
+ Spanish version.
+ - Fixed animations speed (they were running two times slower than in the
+ original engine).
+ - Fixed noise at start and/or end of speech. This was most noticeable
+ with the Spanish speech.
+ - Fixed delay when interacting with the verb menu and the inventory.
+ - Fixed possibility to pick up the axe in the castle multiple times.
+
+ Gob:
+ - Fixed lock up for some games during sound initialization.
+
+ KYRA:
+ - Fixed potential crash when using swamp snake potion on the rat in Hand
+ of Fate. (NOTE: This fix was included in version 1.8.0, but it was not
+ added to the NEWS file).
+ - Fixed missing voice reactions when hitting enemies in CD version of
+ Lands of Lore.
+
+ Lab:
+ - Fixed lock-up during ending sequence.
+ - Improved internal game controls.
+ - Fixed lock-up during some in-game animations.
+
+ SAGA:
+ - Fixed user interface colors in the French and German versions of I Have No
+ Mouth and I Must Scream.
+
+ SCI:
+ - Make cursor workarounds work properly on OpenPandora (and other devices, that
+ support touch screen and analog sticks/mouse at the same time)
+ - Script patch to fix broken ending battle in multilingual King's Quest 5
+ (French, German + Spanish versions are all broken)
+ - Fixed invalid memory access, when loading broken King's Quest 5 credit music track
+ - Fixed lowres/hires issues in King's Quest 6 when saving, changing the lowres/hires
+ setting and restoring the saved game afterwards.
+
+ SCUMM:
+ - Fixed detection of Maniac Mansion from Day of the Tentacle in the Windows
+ version of ScummVM.
+ - Fixed a sound effect not stopping in Loom EGA with AdLib.
+
+ Broken Sword 2.5:
+ - Added option to use English speech instead of German one when no speech is
+ available for the selected language.
+ - Fixed resource releasing on game exit.
+ - Fixed game restart after language change in-game.
+ - Fixed flickering in main Menu.
+ - Fixed long save time on Windows.
+
+ Windows port:
+ - Fixed bug in MIDI device listing affecting cases where MIDI devices were
+ not usable.
+
+ Mac OS X port:
+ - Dock menu for ScummVM now lists recently played games when ScummVM is
+ not running and allows starting those games.
+ - Enabled Sparkle application updater.
+
+ GCW0 port:
+ - Improved support for built-in ScummVM documentation.
1.8.0 (2016-03-04)
New Games:
@@ -1795,3 +1929,4 @@ For a more comprehensive changelog of the latest experimental code, see:
0.0.1 (2001-10-08)
- Initial version.
+
diff --git a/README b/README
index 3d181695c6..353d25d9d0 100644
--- a/README
+++ b/README
@@ -835,7 +835,7 @@ then consult:
<http://wiki.scummvm.org/index.php/HOWTO-Mac_Games>
Although it primarily talks about SCUMM games, it mentions the
-"HFVExplorer" utility which you need to extract the files. Note that you
+"HFSExplorer" utility which you need to extract the files. Note that you
have to put the speech data "Inherit the Earth Voices" in the same
directory as the game data which is stored in:
@@ -1205,7 +1205,7 @@ a Macintosh for this, accessing the CD/floppy data might be tricky. The
reason for this is that the mac uses a special disk format called HFS
which other systems usually do not support. However, there are various
free tools which allow reading such HFS volumes. For example
-"HFVExplorer" for Windows and "hfsutils" for Linux and other Unix-like
+"HFSExplorer" for Windows and "hfsutils" for Linux and other Unix-like
operating systems.
Most of the newer games on the Macintosh shipped with only a single data
@@ -1742,8 +1742,8 @@ The platforms that currently have a different default directory are:
$HOME/Documents/ScummVM Savegames/
Other unices:
- We follow the XDG Base Directory Specification. This means our
- configuration can be found in:
+ We follow the XDG Base Directory Specification. This means by default
+ saved games can be found in:
$XDG_DATA_HOME/scummvm/saves/
If XDG_DATA_HOME is not defined or empty, ~/.local/share will be used
diff --git a/audio/adlib.cpp b/audio/adlib.cpp
index f609164495..3e3f5c047c 100644
--- a/audio/adlib.cpp
+++ b/audio/adlib.cpp
@@ -20,7 +20,6 @@
*
*/
-#include "audio/softsynth/emumidi.h"
#include "common/debug.h"
#include "common/error.h"
#include "common/scummsys.h"
diff --git a/audio/decoders/3do.cpp b/audio/decoders/3do.cpp
index 6d558d4c8c..60cc515fdd 100644
--- a/audio/decoders/3do.cpp
+++ b/audio/decoders/3do.cpp
@@ -25,7 +25,6 @@
#include "common/util.h"
#include "audio/decoders/3do.h"
-#include "audio/decoders/raw.h"
#include "audio/decoders/adpcm_intern.h"
namespace Audio {
diff --git a/audio/decoders/3do.h b/audio/decoders/3do.h
index 7524358543..7f617c6643 100644
--- a/audio/decoders/3do.h
+++ b/audio/decoders/3do.h
@@ -31,19 +31,12 @@
#include "common/scummsys.h"
#include "common/types.h"
-#include "common/substream.h"
+#include "common/stream.h"
#include "audio/audiostream.h"
-#include "audio/decoders/raw.h"
-
-namespace Common {
-class SeekableReadStream;
-}
namespace Audio {
-class SeekableAudioStream;
-
// amount of bytes to be used within the decoder classes as buffers
#define AUDIO_3DO_CACHE_SIZE 1024
diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp
index fe5eec5dcc..ffb61a49c0 100644
--- a/audio/decoders/adpcm.cpp
+++ b/audio/decoders/adpcm.cpp
@@ -320,10 +320,11 @@ int MS_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
_decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f);
_decodedSamples[_decodedSampleCount++] = decodeMS(&_status.ch[_channels - 1], data & 0x0f);
}
+ _decodedSampleIndex = 0;
}
- // (1 - (count - 1)) ensures that _decodedSamples acts as a FIFO of depth 2
- buffer[samples] = _decodedSamples[1 - (_decodedSampleCount - 1)];
+ // _decodedSamples acts as a FIFO of depth 2 or 4;
+ buffer[samples] = _decodedSamples[_decodedSampleIndex++];
_decodedSampleCount--;
}
@@ -433,7 +434,7 @@ int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) {
return samp;
}
-RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, ADPCMType type, int rate, int channels, uint32 blockAlign) {
+SeekableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, ADPCMType type, int rate, int channels, uint32 blockAlign) {
// If size is 0, report the entire size of the stream
if (!size)
size = stream->size();
diff --git a/audio/decoders/adpcm.h b/audio/decoders/adpcm.h
index 650bc341b3..353fd3b71d 100644
--- a/audio/decoders/adpcm.h
+++ b/audio/decoders/adpcm.h
@@ -45,7 +45,7 @@ class SeekableReadStream;
namespace Audio {
class PacketizedAudioStream;
-class RewindableAudioStream;
+class SeekableAudioStream;
// There are several types of ADPCM encoding, only some are supported here
// For all the different encodings, refer to:
@@ -74,7 +74,7 @@ enum ADPCMType {
* @param blockAlign block alignment ???
* @return a new RewindableAudioStream, or NULL, if an error occurred
*/
-RewindableAudioStream *makeADPCMStream(
+SeekableAudioStream *makeADPCMStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse,
uint32 size, ADPCMType type,
diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h
index 92be704cca..f4a708c3fc 100644
--- a/audio/decoders/adpcm_intern.h
+++ b/audio/decoders/adpcm_intern.h
@@ -39,7 +39,7 @@
namespace Audio {
-class ADPCMStream : public RewindableAudioStream {
+class ADPCMStream : public SeekableAudioStream {
protected:
Common::DisposablePtr<Common::SeekableReadStream> _stream;
int32 _startpos;
@@ -67,6 +67,8 @@ public:
virtual int getRate() const { return _rate; }
virtual bool rewind();
+ virtual bool seek(const Timestamp &where) { return false; }
+ virtual Timestamp getLength() const { return -1; }
/**
* This table is used by some ADPCM variants (IMA and OKI) to adjust the
@@ -207,6 +209,7 @@ public:
error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM");
memset(&_status, 0, sizeof(_status));
_decodedSampleCount = 0;
+ _decodedSampleIndex = 0;
}
virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos) && (_decodedSampleCount == 0); }
@@ -218,6 +221,7 @@ protected:
private:
uint8 _decodedSampleCount;
+ uint8 _decodedSampleIndex;
int16 _decodedSamples[4];
};
diff --git a/audio/decoders/aiff.cpp b/audio/decoders/aiff.cpp
index e1949ebb07..253b36dec0 100644
--- a/audio/decoders/aiff.cpp
+++ b/audio/decoders/aiff.cpp
@@ -129,6 +129,8 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
foundSSND = true;
/* uint32 offset = */ stream->readUint32BE();
/* uint32 blockAlign = */ stream->readUint32BE();
+ if (dataStream)
+ delete dataStream;
dataStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + length - 8, disposeAfterUse);
break;
case MKTAG('F', 'V', 'E', 'R'):
@@ -154,7 +156,7 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
return 0;
default:
debug(1, "Skipping AIFF '%s' chunk", tag2str(tag));
- break;
+ break;
}
stream->seek(pos + length + (length & 1)); // ensure we're also word-aligned
@@ -203,7 +205,7 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
if (codec == MKTAG('s', 'o', 'w', 't'))
rawFlags |= Audio::FLAG_LITTLE_ENDIAN;
- return makeRawStream(dataStream, rate, rawFlags);
+ return makeRawStream(dataStream, rate, rawFlags);
}
case MKTAG('i', 'm', 'a', '4'):
// TODO: Use QT IMA ADPCM
@@ -212,7 +214,7 @@ RewindableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream, Dispos
case MKTAG('Q', 'D', 'M', '2'):
// TODO: Need to figure out how to integrate this
// (But hopefully never needed)
- warning("Unhandled AIFF-C QDM2 compression");
+ warning("Unhandled AIFF-C QDM2 compression");
break;
case MKTAG('A', 'D', 'P', '4'):
// ADP4 on 3DO
diff --git a/audio/decoders/vorbis.h b/audio/decoders/vorbis.h
index 2b9f6c3df9..49f770269b 100644
--- a/audio/decoders/vorbis.h
+++ b/audio/decoders/vorbis.h
@@ -35,6 +35,7 @@
* - sword25
* - touche
* - tucker
+ * - wintermute
*/
#ifndef AUDIO_VORBIS_H
diff --git a/audio/decoders/wave.cpp b/audio/decoders/wave.cpp
index adee749b37..cdd6412aa8 100644
--- a/audio/decoders/wave.cpp
+++ b/audio/decoders/wave.cpp
@@ -158,7 +158,7 @@ bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate,
return true;
}
-RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
+SeekableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
int size, rate;
byte flags;
uint16 type;
diff --git a/audio/decoders/wave.h b/audio/decoders/wave.h
index 6bc9f72101..a7fb76978c 100644
--- a/audio/decoders/wave.h
+++ b/audio/decoders/wave.h
@@ -56,7 +56,7 @@ class SeekableReadStream;
namespace Audio {
-class RewindableAudioStream;
+class SeekableAudioStream;
/**
* Try to load a WAVE from the given seekable stream. Returns true if
@@ -82,9 +82,9 @@ extern bool loadWAVFromStream(
*
* @param stream the SeekableReadStream from which to read the WAVE data
* @param disposeAfterUse whether to delete the stream after use
- * @return a new RewindableAudioStream, or NULL, if an error occurred
+ * @return a new SeekableAudioStream, or NULL, if an error occurred
*/
-RewindableAudioStream *makeWAVStream(
+SeekableAudioStream *makeWAVStream(
Common::SeekableReadStream *stream,
DisposeAfterUse::Flag disposeAfterUse);
diff --git a/audio/miles_adlib.cpp b/audio/miles_adlib.cpp
index bf5c9d4a73..0693d1e7ac 100644
--- a/audio/miles_adlib.cpp
+++ b/audio/miles_adlib.cpp
@@ -27,7 +27,6 @@
#include "common/textconsole.h"
#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
namespace Audio {
diff --git a/audio/mods/maxtrax.cpp b/audio/mods/maxtrax.cpp
index f5754a5f96..b0cdaef95a 100644
--- a/audio/mods/maxtrax.cpp
+++ b/audio/mods/maxtrax.cpp
@@ -708,7 +708,7 @@ int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, ui
voiceNum = pickvoice((channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 1 : 0, pri);
} else {
VoiceContext *voice = ARRAYEND(_voiceCtx);
- for (voiceNum = ARRAYSIZE(_voiceCtx); voiceNum-- != 0 && --voice->channel != &channel;)
+ for (voiceNum = ARRAYSIZE(_voiceCtx); voiceNum >= 0 && voice->channel != &channel; voiceNum--, voice--)
;
if (voiceNum < 0)
voiceNum = pickvoice((channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 1 : 0, pri);
diff --git a/audio/mods/protracker.cpp b/audio/mods/protracker.cpp
index 2578e9488a..ce52b61e04 100644
--- a/audio/mods/protracker.cpp
+++ b/audio/mods/protracker.cpp
@@ -24,8 +24,6 @@
#include "audio/mods/paula.h"
#include "audio/mods/module.h"
-#include "audio/audiostream.h"
-
#include "common/textconsole.h"
namespace Modules {
diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.h b/audio/softsynth/fmtowns_pc98/towns_audio.h
index 93eeafb046..0003f02777 100644
--- a/audio/softsynth/fmtowns_pc98/towns_audio.h
+++ b/audio/softsynth/fmtowns_pc98/towns_audio.h
@@ -23,7 +23,9 @@
#ifndef TOWNS_AUDIO_H
#define TOWNS_AUDIO_H
-#include "audio/mixer.h"
+namespace Audio {
+class Mixer;
+}
class TownsAudioInterfaceInternal;
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 685ee99e6f..d536429f4e 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -1043,12 +1043,12 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
if (value & 0x10) {
_timers[0].smpTillCb = _timers[0].smpPerCb;
- _timers[0].smpTillCbRem = _timers[0].smpTillCbRem;
+ _timers[0].smpTillCbRem = _timers[0].smpPerCbRem;
}
if (value & 0x20) {
_timers[1].smpTillCb = _timers[1].smpPerCb;
- _timers[1].smpTillCbRem = _timers[1].smpTillCbRem;
+ _timers[1].smpTillCbRem = _timers[1].smpPerCbRem;
}
} else if (l == 2) {
// LFO
diff --git a/audio/softsynth/mt32.cpp b/audio/softsynth/mt32.cpp
index 4420657854..d514e64fe9 100644
--- a/audio/softsynth/mt32.cpp
+++ b/audio/softsynth/mt32.cpp
@@ -140,10 +140,7 @@ MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixe
}
_reportHandler = NULL;
_synth = NULL;
- // Unfortunately bugs in the emulator cause inaccurate tuning
- // at rates other than 32KHz, thus we produce data at 32KHz and
- // rely on Mixer to convert.
- _outputRate = 32000; //_mixer->getOutputRate();
+ _outputRate = 0;
_initializing = false;
// Initialized in open()
@@ -180,7 +177,6 @@ int MidiDriver_MT32::open() {
if (_isOpen)
return MERR_ALREADY_OPEN;
- MidiDriver_Emulated::open();
_reportHandler = new MT32Emu::ReportHandlerScummVM();
_synth = new MT32Emu::Synth(_reportHandler);
@@ -212,6 +208,18 @@ int MidiDriver_MT32::open() {
double gain = (double)ConfMan.getInt("midi_gain") / 100.0;
_synth->setOutputGain(1.0f * gain);
_synth->setReverbOutputGain(0.68f * gain);
+ // We let the synthesizer play MIDI messages immediately. Our MIDI
+ // handling is synchronous to sample generation. This makes delaying MIDI
+ // events result in odd sound output in some cases. For example, the
+ // shattering window in the Indiana Jones and the Fate of Atlantis intro
+ // will sound like a bell if we use any delay here.
+ // Bug #6242 "AUDIO: Built-In MT-32 MUNT Produces Wrong Sounds".
+ _synth->setMIDIDelayMode(MT32Emu::MIDIDelayMode_IMMEDIATE);
+
+ // We need to report the sample rate MUNT renders at as sample rate of our
+ // AudioStream.
+ _outputRate = _synth->getStereoOutputSampleRate();
+ MidiDriver_Emulated::open();
_initializing = false;
diff --git a/backends/audiocd/audiocd-stream.cpp b/backends/audiocd/audiocd-stream.cpp
new file mode 100644
index 0000000000..3c0d0957da
--- /dev/null
+++ b/backends/audiocd/audiocd-stream.cpp
@@ -0,0 +1,199 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#include "backends/audiocd/audiocd-stream.h"
+#include "common/textconsole.h"
+
+AudioCDStream::AudioCDStream() : _buffer(), _frame(0), _bufferPos(0), _bufferFrame(0), _forceStop(false) {
+}
+
+AudioCDStream::~AudioCDStream() {
+ // Stop the timer; the subclass needs to do this,
+ // so this is just a last resort.
+ stopTimer();
+
+ // Clear any buffered frames
+ emptyQueue();
+}
+
+int AudioCDStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samples = 0;
+
+ // See if any data is left first
+ while (_bufferPos < kSamplesPerFrame && samples < numSamples)
+ buffer[samples++] = _buffer[_bufferPos++];
+
+ // Bail out if done
+ if (endOfData())
+ return samples;
+
+ while (samples < numSamples && !endOfData()) {
+ if (!readNextFrame())
+ return samples;
+
+ // Copy the samples over
+ for (_bufferPos = 0; _bufferPos < kSamplesPerFrame && samples < numSamples;)
+ buffer[samples++] = _buffer[_bufferPos++];
+ }
+
+ return samples;
+}
+
+bool AudioCDStream::readNextFrame() {
+ // Fetch a frame from the queue
+ int16 *buffer;
+
+ {
+ Common::StackLock lock(_mutex);
+
+ // Nothing we can do if it's empty
+ if (_bufferQueue.empty())
+ return false;
+
+ buffer = _bufferQueue.pop();
+ }
+
+ memcpy(_buffer, buffer, kSamplesPerFrame * 2);
+ delete[] buffer;
+ _frame++;
+ return true;
+}
+
+bool AudioCDStream::endOfData() const {
+ return !shouldForceStop() && getStartFrame() + _frame >= getEndFrame() && _bufferPos == kSamplesPerFrame;
+}
+
+bool AudioCDStream::seek(const Audio::Timestamp &where) {
+ // Stop the timer
+ stopTimer();
+
+ // Clear anything out of the queue
+ emptyQueue();
+
+ // Convert to the frame number
+ // Really not much else needed
+ _bufferPos = kSamplesPerFrame;
+ _frame = where.convertToFramerate(kFramesPerSecond).totalNumberOfFrames();
+ _bufferFrame = _frame;
+
+ // Start the timer again
+ startTimer();
+ return true;
+}
+
+Audio::Timestamp AudioCDStream::getLength() const {
+ return Audio::Timestamp(0, getEndFrame() - getStartFrame(), kFramesPerSecond);
+}
+
+void AudioCDStream::timerProc(void *refCon) {
+ static_cast<AudioCDStream *>(refCon)->onTimer();
+}
+
+void AudioCDStream::onTimer() {
+ // The goal here is to do as much work in this timer instead
+ // of doing it in the readBuffer() call, which is the mixer.
+
+ // If we're done, bail.
+ if (shouldForceStop() || getStartFrame() + _bufferFrame >= getEndFrame())
+ return;
+
+ // Get a quick count of the number of items in the queue
+ // We don't care that much; we only need a quick estimate
+ _mutex.lock();
+ uint32 queueCount = _bufferQueue.size();
+ _mutex.unlock();
+
+ // If we have enough audio buffered, bail out
+ if (queueCount >= kBufferThreshold)
+ return;
+
+ while (!shouldForceStop() && queueCount < kBufferThreshold && getStartFrame() + _bufferFrame < getEndFrame()) {
+ int16 *buffer = new int16[kSamplesPerFrame];
+
+ // Figure out the MSF of the frame we're looking for
+ int frame = _bufferFrame + getStartFrame();
+
+ // Request to read that frame
+ if (!readFrame(frame, buffer)) {
+ warning("Failed to read CD audio");
+ forceStop();
+ return;
+ }
+
+ _bufferFrame++;
+
+ // Now push the buffer onto the queue
+ Common::StackLock lock(_mutex);
+ _bufferQueue.push(buffer);
+ queueCount = _bufferQueue.size();
+ }
+}
+
+void AudioCDStream::startTimer(bool fillBuffer) {
+ _forceStop = false;
+ if (fillBuffer) {
+ onTimer();
+ }
+ g_system->getTimerManager()->installTimerProc(timerProc, 10 * 1000, this, "AudioCDStream");
+}
+
+void AudioCDStream::stopTimer() {
+ forceStop();
+ g_system->getTimerManager()->removeTimerProc(timerProc);
+}
+
+void AudioCDStream::emptyQueue() {
+ while (!_bufferQueue.empty())
+ delete[] _bufferQueue.pop();
+}
+
+bool AudioCDStream::shouldForceStop() const {
+ Common::StackLock lock(_forceStopMutex);
+ return _forceStop;
+}
+
+void AudioCDStream::forceStop() {
+ Common::StackLock lock(_forceStopMutex);
+ _forceStop = true;
+}
diff --git a/backends/audiocd/audiocd-stream.h b/backends/audiocd/audiocd-stream.h
new file mode 100644
index 0000000000..dbc6a6321b
--- /dev/null
+++ b/backends/audiocd/audiocd-stream.h
@@ -0,0 +1,108 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifndef BACKENDS_AUDIOCD_AUDIOCD_STREAM_H
+#define BACKENDS_AUDIOCD_AUDIOCD_STREAM_H
+
+#include "audio/audiostream.h"
+#include "common/mutex.h"
+#include "common/queue.h"
+#include "common/timer.h"
+
+class AudioCDStream : public Audio::SeekableAudioStream {
+public:
+ AudioCDStream();
+ ~AudioCDStream();
+
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return true; }
+ int getRate() const { return 44100; }
+ bool endOfData() const;
+ bool seek(const Audio::Timestamp &where);
+ Audio::Timestamp getLength() const;
+
+protected:
+ virtual uint getStartFrame() const = 0;
+ virtual uint getEndFrame() const = 0;
+ virtual bool readFrame(int frame, int16 *buffer) = 0;
+
+ void startTimer(bool fillBuffer = false);
+ void stopTimer();
+
+ enum {
+ kBytesPerFrame = 2352,
+ kSamplesPerFrame = kBytesPerFrame / 2
+ };
+
+ enum {
+ kSecondsPerMinute = 60,
+ kFramesPerSecond = 75
+ };
+
+ enum {
+ // Keep about a second's worth of audio in the buffer
+ kBufferThreshold = kFramesPerSecond
+ };
+
+private:
+ int16 _buffer[kSamplesPerFrame];
+ int _frame;
+ uint _bufferPos;
+
+ Common::Queue<int16 *> _bufferQueue;
+ int _bufferFrame;
+ Common::Mutex _mutex;
+
+ bool _forceStop;
+ bool shouldForceStop() const;
+ void forceStop();
+ Common::Mutex _forceStopMutex;
+
+ bool readNextFrame();
+ static void timerProc(void *refCon);
+ void onTimer();
+ void emptyQueue();
+};
+
+#endif
diff --git a/backends/audiocd/audiocd.h b/backends/audiocd/audiocd.h
index 6eae8e096b..b3674f2570 100644
--- a/backends/audiocd/audiocd.h
+++ b/backends/audiocd/audiocd.h
@@ -48,26 +48,31 @@ public:
};
/**
- * @name Emulated playback functions
- * Engines should call these functions. Not all platforms
- * support cd playback, and these functions should try to
- * emulate it.
+ * Initialize the specified CD drive for audio playback.
+ * @return true if the CD drive was inited successfully
+ */
+ virtual bool open() = 0;
+
+ /**
+ * Close the currently open CD drive
*/
- //@{
+ virtual void close() = 0;
/**
* Start audio CD playback
- * @param track the track to play.
- * @param numLoops how often playback should be repeated (-1 = infinitely often).
- * @param startFrame the frame at which playback should start (75 frames = 1 second).
- * @param duration the number of frames to play.
- * @param only_emulate determines if the track should be emulated only
+ * @param track the track to play.
+ * @param numLoops how often playback should be repeated (<=0 means infinitely often).
+ * @param startFrame the frame at which playback should start (75 frames = 1 second).
+ * @param duration the number of frames to play.
+ * @param onlyEmulate determines if the track should be emulated only
+ * @note The @c onlyEmulate parameter is deprecated.
+ * @return @c true if the track started playing, @c false otherwise
*/
- virtual void play(int track, int numLoops, int startFrame, int duration, bool only_emulate = false) = 0;
+ virtual bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false) = 0;
/**
* Get if audio is being played.
- * @return true if CD or emulated audio is playing
+ * @return true if CD audio is playing
*/
virtual bool isPlaying() const = 0;
@@ -82,12 +87,12 @@ public:
virtual void setBalance(int8 balance) = 0;
/**
- * Stop CD or emulated audio playback.
+ * Stop audio playback.
*/
virtual void stop() = 0;
/**
- * Update CD or emulated audio status.
+ * Update audio status.
*/
virtual void update() = 0;
@@ -96,50 +101,6 @@ public:
* @return a Status struct with playback data.
*/
virtual Status getStatus() const = 0;
-
- //@}
-
-
- /**
- * @name Real CD audio methods
- * These functions should be called from the emulated
- * ones if they can't emulate the audio playback.
- */
- //@{
-
- /**
- * Initialize the specified CD drive for audio playback.
- * @param drive the drive id
- * @return true if the CD drive was inited successfully
- */
- virtual bool openCD(int drive) = 0;
-
- /**
- * Poll CD status.
- * @return true if CD audio is playing
- */
- virtual bool pollCD() const = 0;
-
- /**
- * Start CD audio playback.
- * @param track the track to play.
- * @param num_loops how often playback should be repeated (-1 = infinitely often).
- * @param start_frame the frame at which playback should start (75 frames = 1 second).
- * @param duration the number of frames to play.
- */
- virtual void playCD(int track, int num_loops, int start_frame, int duration) = 0;
-
- /**
- * Stop CD audio playback.
- */
- virtual void stopCD() = 0;
-
- /**
- * Update CD audio status.
- */
- virtual void updateCD() = 0;
-
- //@}
};
#endif
diff --git a/backends/audiocd/default/default-audiocd.cpp b/backends/audiocd/default/default-audiocd.cpp
index abf80ac4cd..c2ce7cedcc 100644
--- a/backends/audiocd/default/default-audiocd.cpp
+++ b/backends/audiocd/default/default-audiocd.cpp
@@ -22,6 +22,7 @@
#include "backends/audiocd/default/default-audiocd.h"
#include "audio/audiostream.h"
+#include "common/config-manager.h"
#include "common/system.h"
DefaultAudioCDManager::DefaultAudioCDManager() {
@@ -37,7 +38,25 @@ DefaultAudioCDManager::DefaultAudioCDManager() {
assert(_mixer);
}
-void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool only_emulate) {
+DefaultAudioCDManager::~DefaultAudioCDManager() {
+ // Subclasses should call close as well
+ close();
+}
+
+bool DefaultAudioCDManager::open() {
+ // For emulation, opening is always valid
+ close();
+ return true;
+}
+
+void DefaultAudioCDManager::close() {
+ // Only need to stop for emulation
+ stop();
+}
+
+bool DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
+ stop();
+
if (numLoops != 0 || startFrame != 0) {
_cd.track = track;
_cd.numLoops = numLoops;
@@ -55,9 +74,6 @@ void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int du
for (int i = 0; !stream && i < 2; ++i)
stream = Audio::SeekableAudioStream::openStreamFile(trackName[i]);
- // Stop any currently playing emulated track
- _mixer->stopHandle(_handle);
-
if (stream != 0) {
Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : stream->getLength();
@@ -70,12 +86,11 @@ void DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int du
_emulating = true;
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
- } else {
- _emulating = false;
- if (!only_emulate)
- playCD(track, numLoops, startFrame, duration);
+ return true;
}
}
+
+ return false;
}
void DefaultAudioCDManager::stop() {
@@ -83,52 +98,32 @@ void DefaultAudioCDManager::stop() {
// Audio CD emulation
_mixer->stopHandle(_handle);
_emulating = false;
- } else {
- // Real Audio CD
- stopCD();
}
}
bool DefaultAudioCDManager::isPlaying() const {
- if (_emulating) {
- // Audio CD emulation
+ // Audio CD emulation
+ if (_emulating)
return _mixer->isSoundHandleActive(_handle);
- } else {
- // Real Audio CD
- return pollCD();
- }
+
+ // The default class only handles emulation
+ return false;
}
void DefaultAudioCDManager::setVolume(byte volume) {
_cd.volume = volume;
- if (_emulating) {
- // Audio CD emulation
- if (_mixer->isSoundHandleActive(_handle))
- _mixer->setChannelVolume(_handle, _cd.volume);
- } else {
- // Real Audio CD
- // Unfortunately I can't implement this atm
- // since SDL doesn't seem to offer an interface method for this.
-
- // g_system->setVolumeCD(_cd.volume);
- }
+ // Audio CD emulation
+ if (_emulating && isPlaying())
+ _mixer->setChannelVolume(_handle, _cd.volume);
}
void DefaultAudioCDManager::setBalance(int8 balance) {
_cd.balance = balance;
- if (_emulating) {
- // Audio CD emulation
- if (isPlaying())
- _mixer->setChannelBalance(_handle, _cd.balance);
- } else {
- // Real Audio CD
- // Unfortunately I can't implement this atm
- // since SDL doesn't seem to offer an interface method for this.
-
- // g_system->setBalanceCD(_cd.balance);
- }
+ // Audio CD emulation
+ if (_emulating && isPlaying())
+ _mixer->setChannelBalance(_handle, _cd.balance);
}
void DefaultAudioCDManager::update() {
@@ -142,8 +137,6 @@ void DefaultAudioCDManager::update() {
// or not.
_emulating = false;
}
- } else {
- updateCD();
}
}
@@ -152,3 +145,21 @@ DefaultAudioCDManager::Status DefaultAudioCDManager::getStatus() const {
info.playing = isPlaying();
return info;
}
+
+bool DefaultAudioCDManager::openRealCD() {
+ Common::String cdrom = ConfMan.get("cdrom");
+
+ // Try to parse it as an int
+ char *endPos;
+ int drive = strtol(cdrom.c_str(), &endPos, 0);
+
+ // If not an integer, treat as a drive path
+ if (endPos == cdrom.c_str())
+ return openCD(cdrom);
+
+ if (drive < 0)
+ return false;
+
+ return openCD(drive);
+}
+
diff --git a/backends/audiocd/default/default-audiocd.h b/backends/audiocd/default/default-audiocd.h
index 9e4ba6b33e..e3fbb4b5a1 100644
--- a/backends/audiocd/default/default-audiocd.h
+++ b/backends/audiocd/default/default-audiocd.h
@@ -26,29 +26,48 @@
#include "backends/audiocd/audiocd.h"
#include "audio/mixer.h"
+namespace Common {
+class String;
+} // End of namespace Common
+
/**
* The default audio cd manager. Implements emulation of audio cd playback.
*/
class DefaultAudioCDManager : public AudioCDManager {
public:
DefaultAudioCDManager();
- virtual ~DefaultAudioCDManager() {}
-
- void play(int track, int numLoops, int startFrame, int duration, bool only_emulate = false);
- void stop();
- bool isPlaying() const;
- void setVolume(byte volume);
- void setBalance(int8 balance);
- void update();
+ virtual ~DefaultAudioCDManager();
+
+ virtual bool open();
+ virtual void close();
+ virtual bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
+ virtual void stop();
+ virtual bool isPlaying() const;
+ virtual void setVolume(byte volume);
+ virtual void setBalance(int8 balance);
+ virtual void update();
virtual Status getStatus() const; // Subclasses should override for better status results
+protected:
+ /**
+ * Open a CD using the cdrom config variable
+ */
+ bool openRealCD();
+
+ /**
+ * Open a CD using the specified drive index
+ * @param drive The index of the drive
+ * @note The index is implementation-defined, but 0 is always the best choice
+ */
virtual bool openCD(int drive) { return false; }
- virtual void updateCD() {}
- virtual bool pollCD() const { return false; }
- virtual void playCD(int track, int num_loops, int start_frame, int duration) {}
- virtual void stopCD() {}
-protected:
+ /**
+ * Open a CD from a specific drive
+ * @param drive The name of the drive/path
+ * @note The drive parameter is platform-specific
+ */
+ virtual bool openCD(const Common::String &drive) { return false; }
+
Audio::SoundHandle _handle;
bool _emulating;
diff --git a/backends/audiocd/linux/linux-audiocd.cpp b/backends/audiocd/linux/linux-audiocd.cpp
new file mode 100644
index 0000000000..caa0265637
--- /dev/null
+++ b/backends/audiocd/linux/linux-audiocd.cpp
@@ -0,0 +1,471 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+// Enable all forbidden symbols to allow us to include and use necessary APIs.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "backends/audiocd/linux/linux-audiocd.h"
+
+#ifdef USE_LINUXCD
+
+#include "backends/audiocd/audiocd-stream.h"
+#include "backends/audiocd/default/default-audiocd.h"
+#include "common/array.h"
+#include "common/config-manager.h"
+#include "common/str.h"
+#include "common/debug.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/cdrom.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+enum {
+ kLeadoutTrack = 0xAA
+};
+
+enum {
+ kBytesPerFrame = 2352,
+ kSamplesPerFrame = kBytesPerFrame / 2
+};
+
+enum {
+ kSecondsPerMinute = 60,
+ kFramesPerSecond = 75
+};
+
+enum {
+ // Keep about a second's worth of audio in the buffer
+ kBufferThreshold = kFramesPerSecond
+};
+
+static int getFrameCount(const cdrom_msf0 &msf) {
+ int time = msf.minute;
+ time *= kSecondsPerMinute;
+ time += msf.second;
+ time *= kFramesPerSecond;
+ time += msf.frame;
+ return time;
+}
+
+// Helper function to convert an error code into a human-readable message
+static Common::String getErrorMessage(int errorCode) {
+ char buf[256];
+ buf[0] = 0;
+
+#ifdef _GNU_SOURCE
+ // glibc sucks
+ return Common::String(strerror_r(errorCode, buf, sizeof(buf)));
+#else
+ strerror_r(errorCode, buf, sizeof(buf));
+ return Common::String(buf);
+#endif
+}
+
+class LinuxAudioCDStream : public AudioCDStream {
+public:
+ LinuxAudioCDStream(int fd, const cdrom_tocentry &startEntry, const cdrom_tocentry &endEntry);
+ ~LinuxAudioCDStream();
+
+protected:
+ uint getStartFrame() const;
+ uint getEndFrame() const;
+ bool readFrame(int frame, int16 *buffer);
+
+private:
+ int _fd;
+ const cdrom_tocentry &_startEntry, &_endEntry;
+};
+
+LinuxAudioCDStream::LinuxAudioCDStream(int fd, const cdrom_tocentry &startEntry, const cdrom_tocentry &endEntry) :
+ _fd(fd), _startEntry(startEntry), _endEntry(endEntry) {
+ // We fill the buffer here already to prevent any out of sync issues due
+ // to the CD not yet having spun up.
+ startTimer(true);
+}
+
+LinuxAudioCDStream::~LinuxAudioCDStream() {
+ stopTimer();
+}
+
+bool LinuxAudioCDStream::readFrame(int frame, int16 *buffer) {
+ // Create the argument
+ union {
+ cdrom_msf msf;
+ char buffer[kBytesPerFrame];
+ } arg;
+
+ int seconds = frame / kFramesPerSecond;
+ frame %= kFramesPerSecond;
+ int minutes = seconds / kSecondsPerMinute;
+ seconds %= kSecondsPerMinute;
+
+ // Request to read that frame
+ // We don't use CDROMREADAUDIO, as it seems to cause kernel
+ // panics on ejecting discs. Probably bad to eject the disc
+ // while playing, but at least let's try to prevent that case.
+ arg.msf.cdmsf_min0 = minutes;
+ arg.msf.cdmsf_sec0 = seconds;
+ arg.msf.cdmsf_frame0 = frame;
+ // The "end" part is irrelevant (why isn't cdrom_msf0 the type
+ // instead?)
+
+ if (ioctl(_fd, CDROMREADRAW, &arg) < 0) {
+ warning("Failed to CD read audio: %s", getErrorMessage(errno).c_str());
+ return false;
+ }
+
+ memcpy(buffer, arg.buffer, kBytesPerFrame);
+ return true;
+}
+
+uint LinuxAudioCDStream::getStartFrame() const {
+ return getFrameCount(_startEntry.cdte_addr.msf);
+}
+
+uint LinuxAudioCDStream::getEndFrame() const {
+ return getFrameCount(_endEntry.cdte_addr.msf);
+}
+
+
+class LinuxAudioCDManager : public DefaultAudioCDManager {
+public:
+ LinuxAudioCDManager();
+ ~LinuxAudioCDManager();
+
+ bool open();
+ void close();
+ bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
+
+protected:
+ bool openCD(int drive);
+ bool openCD(const Common::String &drive);
+
+private:
+ struct Device {
+ Device(const Common::String &n, dev_t d) : name(n), device(d) {}
+ Common::String name;
+ dev_t device;
+ };
+
+ typedef Common::Array<Device> DeviceList;
+ DeviceList scanDevices();
+ bool tryAddDrive(DeviceList &devices, const Common::String &drive);
+ bool tryAddDrive(DeviceList &devices, const Common::String &drive, dev_t device);
+ bool tryAddDrive(DeviceList &devices, dev_t device);
+ bool tryAddPath(DeviceList &devices, const Common::String &path);
+ bool tryAddGamePath(DeviceList &devices);
+ bool loadTOC();
+ static bool hasDevice(const DeviceList &devices, dev_t device);
+
+ int _fd;
+ cdrom_tochdr _tocHeader;
+ Common::Array<cdrom_tocentry> _tocEntries;
+};
+
+static bool isTrayEmpty(int errorNumber) {
+ switch (errorNumber) {
+ case EIO:
+ case ENOENT:
+ case EINVAL:
+#ifdef ENOMEDIUM
+ case ENOMEDIUM:
+#endif
+ return true;
+ }
+
+ return false;
+}
+
+LinuxAudioCDManager::LinuxAudioCDManager() {
+ _fd = -1;
+ memset(&_tocHeader, 0, sizeof(_tocHeader));
+}
+
+LinuxAudioCDManager::~LinuxAudioCDManager() {
+ close();
+}
+
+bool LinuxAudioCDManager::open() {
+ close();
+
+ if (openRealCD())
+ return true;
+
+ return DefaultAudioCDManager::open();
+}
+
+void LinuxAudioCDManager::close() {
+ DefaultAudioCDManager::close();
+
+ if (_fd < 0)
+ return;
+
+ ::close(_fd);
+ memset(&_tocHeader, 0, sizeof(_tocHeader));
+ _tocEntries.clear();
+}
+
+bool LinuxAudioCDManager::openCD(int drive) {
+ DeviceList devices = scanDevices();
+ if (drive >= (int)devices.size())
+ return false;
+
+ _fd = ::open(devices[drive].name.c_str(), O_RDONLY | O_NONBLOCK, 0);
+ if (_fd < 0)
+ return false;
+
+ if (!loadTOC()) {
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+bool LinuxAudioCDManager::openCD(const Common::String &drive) {
+ DeviceList devices;
+ if (!tryAddDrive(devices, drive) && !tryAddPath(devices, drive))
+ return false;
+
+ _fd = ::open(devices[0].name.c_str(), O_RDONLY | O_NONBLOCK, 0);
+ if (_fd < 0)
+ return false;
+
+ if (!loadTOC()) {
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+bool LinuxAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
+ // Prefer emulation
+ if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
+ return true;
+
+ // If we're set to only emulate, or have no CD drive, return here
+ if (onlyEmulate || _fd < 0)
+ return false;
+
+ // HACK: For now, just assume that track number is right
+ // That only works because ScummVM uses the wrong track number anyway
+
+ if (track >= (int)_tocEntries.size() - 1) {
+ warning("No such track %d", track);
+ return false;
+ }
+
+ // Bail if the track isn't an audio track
+ if ((_tocEntries[track].cdte_ctrl & 0x04) != 0) {
+ warning("Track %d is not audio", track);
+ return false;
+ }
+
+ // Create the AudioStream and play it
+ debug(1, "Playing CD track %d", track);
+
+ Audio::SeekableAudioStream *audioStream = new LinuxAudioCDStream(_fd, _tocEntries[track], _tocEntries[track + 1]);
+
+ Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
+ Audio::Timestamp end = (duration == 0) ? audioStream->getLength() : Audio::Timestamp(0, startFrame + duration, 75);
+
+ // Fake emulation since we're really playing an AudioStream
+ _emulating = true;
+
+ _mixer->playStream(
+ Audio::Mixer::kMusicSoundType,
+ &_handle,
+ Audio::makeLoopingAudioStream(audioStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops),
+ -1,
+ _cd.volume,
+ _cd.balance,
+ DisposeAfterUse::YES,
+ true);
+
+ return true;
+}
+
+LinuxAudioCDManager::DeviceList LinuxAudioCDManager::scanDevices() {
+ DeviceList devices;
+
+ // Try to use the game's path first as the device
+ tryAddGamePath(devices);
+
+ // Try adding the default CD-ROM
+ tryAddDrive(devices, "/dev/cdrom");
+
+ // TODO: Try others?
+
+ return devices;
+}
+
+bool LinuxAudioCDManager::tryAddDrive(DeviceList &devices, const Common::String &drive) {
+ struct stat stbuf;
+ if (stat(drive.c_str(), &stbuf) < 0)
+ return false;
+
+ // Must be a character or block device
+ if (!S_ISCHR(stbuf.st_mode) && !S_ISBLK(stbuf.st_mode))
+ return false;
+
+ return tryAddDrive(devices, drive, stbuf.st_rdev);
+}
+
+bool LinuxAudioCDManager::tryAddDrive(DeviceList &devices, const Common::String &drive, dev_t device) {
+ if (hasDevice(devices, device))
+ return true;
+
+ // Try opening the device and seeing if it is a CD-ROM drve
+ int fd = ::open(drive.c_str(), O_RDONLY | O_NONBLOCK, 0);
+ if (fd >= 0) {
+ cdrom_subchnl info;
+ info.cdsc_format = CDROM_MSF;
+
+ bool isCD = ioctl(fd, CDROMSUBCHNL, &info) == 0 || isTrayEmpty(errno);
+ ::close(fd);
+ if (isCD) {
+ devices.push_back(Device(drive, device));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LinuxAudioCDManager::tryAddDrive(DeviceList &devices, dev_t device) {
+ // Construct the block name
+ // TODO: libblkid's blkid_devno_to_devname is exactly what we look for.
+ // This requires an external dependency though.
+ Common::String name = Common::String::format("/dev/block/%d:%d", major(device), minor(device));
+
+ return tryAddDrive(devices, name, device);
+}
+
+bool LinuxAudioCDManager::tryAddPath(DeviceList &devices, const Common::String &path) {
+ struct stat stbuf;
+ if (stat(path.c_str(), &stbuf) < 0)
+ return false;
+
+ return tryAddDrive(devices, stbuf.st_dev);
+}
+
+bool LinuxAudioCDManager::tryAddGamePath(DeviceList &devices) {
+ if (!ConfMan.hasKey("path"))
+ return false;
+
+ return tryAddPath(devices, ConfMan.get("path"));
+}
+
+bool LinuxAudioCDManager::loadTOC() {
+ if (_fd < 0)
+ return false;
+
+ if (ioctl(_fd, CDROMREADTOCHDR, &_tocHeader) < 0)
+ return false;
+
+ debug(4, "CD: Start Track: %d, End Track %d", _tocHeader.cdth_trk0, _tocHeader.cdth_trk1);
+
+ for (int i = _tocHeader.cdth_trk0; i <= _tocHeader.cdth_trk1; i++) {
+ cdrom_tocentry entry;
+ memset(&entry, 0, sizeof(entry));
+ entry.cdte_track = i;
+ entry.cdte_format = CDROM_MSF;
+
+ if (ioctl(_fd, CDROMREADTOCENTRY, &entry) < 0)
+ return false;
+
+#if 0
+ debug("Entry:");
+ debug("\tTrack: %d", entry.cdte_track);
+ debug("\tAdr: %d", entry.cdte_adr);
+ debug("\tCtrl: %d", entry.cdte_ctrl);
+ debug("\tFormat: %d", entry.cdte_format);
+ debug("\tMSF: %d:%d:%d", entry.cdte_addr.msf.minute, entry.cdte_addr.msf.second, entry.cdte_addr.msf.frame);
+ debug("\tMode: %d\n", entry.cdte_datamode);
+#endif
+
+ _tocEntries.push_back(entry);
+ }
+
+ // Fetch the leadout so we can get the length of the last frame
+ cdrom_tocentry entry;
+ memset(&entry, 0, sizeof(entry));
+ entry.cdte_track = kLeadoutTrack;
+ entry.cdte_format = CDROM_MSF;
+
+ if (ioctl(_fd, CDROMREADTOCENTRY, &entry) < 0)
+ return false;
+
+#if 0
+ debug("Lead out:");
+ debug("\tTrack: %d", entry.cdte_track);
+ debug("\tAdr: %d", entry.cdte_adr);
+ debug("\tCtrl: %d", entry.cdte_ctrl);
+ debug("\tFormat: %d", entry.cdte_format);
+ debug("\tMSF: %d:%d:%d", entry.cdte_addr.msf.minute, entry.cdte_addr.msf.second, entry.cdte_addr.msf.frame);
+ debug("\tMode: %d\n", entry.cdte_datamode);
+#endif
+
+ _tocEntries.push_back(entry);
+ return true;
+}
+
+bool LinuxAudioCDManager::hasDevice(const DeviceList &devices, dev_t device) {
+ for (DeviceList::const_iterator it = devices.begin(); it != devices.end(); it++)
+ if (it->device == device)
+ return true;
+
+ return false;
+}
+
+AudioCDManager *createLinuxAudioCDManager() {
+ return new LinuxAudioCDManager();
+}
+
+#endif // USE_LINUXCD
diff --git a/backends/audiocd/linux/linux-audiocd.h b/backends/audiocd/linux/linux-audiocd.h
new file mode 100644
index 0000000000..09d6353991
--- /dev/null
+++ b/backends/audiocd/linux/linux-audiocd.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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifndef BACKENDS_AUDIOCD_LINUX_H
+#define BACKENDS_AUDIOCD_LINUX_H
+
+#include "common/scummsys.h"
+
+#ifdef USE_LINUXCD
+
+class AudioCDManager;
+
+/**
+ * Create an audio CD manager using the Linux CDROM API
+ */
+AudioCDManager *createLinuxAudioCDManager();
+
+#endif
+
+#endif
+
diff --git a/backends/audiocd/macosx/macosx-audiocd.cpp b/backends/audiocd/macosx/macosx-audiocd.cpp
new file mode 100644
index 0000000000..e8d41c3e10
--- /dev/null
+++ b/backends/audiocd/macosx/macosx-audiocd.cpp
@@ -0,0 +1,306 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifdef MACOSX
+
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <limits.h>
+
+#include "common/scummsys.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/aiff.h"
+#include "audio/timestamp.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/fs.h"
+#include "common/hashmap.h"
+#include "common/textconsole.h"
+#include "backends/audiocd/default/default-audiocd.h"
+#include "backends/audiocd/macosx/macosx-audiocd.h"
+#include "backends/fs/stdiostream.h"
+
+// Partially based on SDL's code
+
+/**
+ * The Mac OS X audio cd manager. Implements real audio cd playback.
+ */
+class MacOSXAudioCDManager : public DefaultAudioCDManager {
+public:
+ MacOSXAudioCDManager() {}
+ ~MacOSXAudioCDManager();
+
+ bool open();
+ void close();
+ bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
+
+protected:
+ bool openCD(int drive);
+ bool openCD(const Common::String &drive);
+
+private:
+ struct Drive {
+ Drive(const Common::String &m, const Common::String &d, const Common::String &f) :
+ mountPoint(m), deviceName(d), fsType(f) {}
+
+ Common::String mountPoint;
+ Common::String deviceName;
+ Common::String fsType;
+ };
+
+ typedef Common::Array<Drive> DriveList;
+ DriveList detectAllDrives();
+ DriveList detectCDDADrives();
+
+ bool findTrackNames(const Common::String &drivePath);
+
+ Common::HashMap<uint, Common::String> _trackMap;
+};
+
+MacOSXAudioCDManager::~MacOSXAudioCDManager() {
+ close();
+}
+
+bool MacOSXAudioCDManager::open() {
+ close();
+
+ if (openRealCD())
+ return true;
+
+ return DefaultAudioCDManager::open();
+}
+
+/**
+ * Find the base disk number of device name.
+ * Returns -1 if mount point is not /dev/disk*
+ */
+static int findBaseDiskNumber(const Common::String &diskName) {
+ if (!diskName.hasPrefix("/dev/disk"))
+ return -1;
+
+ const char *startPtr = diskName.c_str() + 9;
+ char *endPtr;
+ int baseDiskNumber = strtol(startPtr, &endPtr, 10);
+ if (startPtr == endPtr)
+ return -1;
+
+ return baseDiskNumber;
+}
+
+bool MacOSXAudioCDManager::openCD(int drive) {
+ DriveList allDrives = detectAllDrives();
+ if (allDrives.empty())
+ return false;
+
+ DriveList cddaDrives;
+
+ // Try to get the volume related to the game's path
+ if (ConfMan.hasKey("path")) {
+ Common::String gamePath = ConfMan.get("path");
+ struct statfs gamePathStat;
+ if (statfs(gamePath.c_str(), &gamePathStat) == 0) {
+ int baseDiskNumber = findBaseDiskNumber(gamePathStat.f_mntfromname);
+ if (baseDiskNumber >= 0) {
+ // Look for a CDDA drive with the same base disk number
+ for (uint32 i = 0; i < allDrives.size(); i++) {
+ if (allDrives[i].fsType == "cddafs" && findBaseDiskNumber(allDrives[i].deviceName) == baseDiskNumber) {
+ debug(1, "Preferring drive '%s'", allDrives[i].mountPoint.c_str());
+ cddaDrives.push_back(allDrives[i]);
+ allDrives.remove_at(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Add the remaining CDDA drives to the CDDA list
+ for (uint32 i = 0; i < allDrives.size(); i++)
+ if (allDrives[i].fsType == "cddafs")
+ cddaDrives.push_back(allDrives[i]);
+
+ if (drive >= (int)cddaDrives.size())
+ return false;
+
+ debug(1, "Using '%s' as the CD drive", cddaDrives[drive].mountPoint.c_str());
+
+ return findTrackNames(cddaDrives[drive].mountPoint);
+}
+
+bool MacOSXAudioCDManager::openCD(const Common::String &drive) {
+ DriveList drives = detectAllDrives();
+
+ for (uint32 i = 0; i < drives.size(); i++) {
+ if (drives[i].fsType != "cddafs")
+ continue;
+
+ if (drives[i].mountPoint == drive || drives[i].deviceName == drive) {
+ debug(1, "Using '%s' as the CD drive", drives[i].mountPoint.c_str());
+ return findTrackNames(drives[i].mountPoint);
+ }
+ }
+
+ return false;
+}
+
+void MacOSXAudioCDManager::close() {
+ DefaultAudioCDManager::close();
+ _trackMap.clear();
+}
+
+enum {
+ // Some crazy high number that we'll never actually hit
+ kMaxDriveCount = 256
+};
+
+MacOSXAudioCDManager::DriveList MacOSXAudioCDManager::detectAllDrives() {
+ // Fetch the lists of drives
+ struct statfs driveStats[kMaxDriveCount];
+ int foundDrives = getfsstat(driveStats, sizeof(driveStats), MNT_WAIT);
+ if (foundDrives <= 0)
+ return DriveList();
+
+ DriveList drives;
+ for (int i = 0; i < foundDrives; i++)
+ drives.push_back(Drive(driveStats[i].f_mntonname, driveStats[i].f_mntfromname, driveStats[i].f_fstypename));
+
+ return drives;
+}
+
+bool MacOSXAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
+ // Prefer emulation
+ if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
+ return true;
+
+ // If we're set to only emulate, or have no CD drive, return here
+ if (onlyEmulate || !_trackMap.contains(track))
+ return false;
+
+ if (!numLoops && !startFrame)
+ return false;
+
+ // Now load the AIFF track from the name
+ Common::String fileName = _trackMap[track];
+ Common::SeekableReadStream *stream = StdioStream::makeFromPath(fileName.c_str(), false);
+
+ if (!stream) {
+ warning("Failed to open track '%s'", fileName.c_str());
+ return false;
+ }
+
+ Audio::AudioStream *audioStream = Audio::makeAIFFStream(stream, DisposeAfterUse::YES);
+ if (!audioStream) {
+ warning("Track '%s' is not an AIFF track", fileName.c_str());
+ return false;
+ }
+
+ Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(audioStream);
+ if (!seekStream) {
+ warning("Track '%s' is not seekable", fileName.c_str());
+ return false;
+ }
+
+ Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
+ Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : seekStream->getLength();
+
+ // Fake emulation since we're really playing an AIFF file
+ _emulating = true;
+
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
+ Audio::makeLoopingAudioStream(seekStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
+ return true;
+}
+
+bool MacOSXAudioCDManager::findTrackNames(const Common::String &drivePath) {
+ Common::FSNode directory(drivePath);
+
+ if (!directory.exists()) {
+ warning("Directory '%s' does not exist", drivePath.c_str());
+ return false;
+ }
+
+ if (!directory.isDirectory()) {
+ warning("'%s' is not a directory", drivePath.c_str());
+ return false;
+ }
+
+ Common::FSList children;
+ if (!directory.getChildren(children, Common::FSNode::kListFilesOnly)) {
+ warning("Failed to find children for '%s'", drivePath.c_str());
+ return false;
+ }
+
+ for (uint32 i = 0; i < children.size(); i++) {
+ if (!children[i].isDirectory()) {
+ Common::String fileName = children[i].getName();
+
+ if (fileName.hasSuffix(".aiff") || fileName.hasSuffix(".cdda")) {
+ uint j = 0;
+
+ // Search for the track ID in the file name.
+ for (; j < fileName.size() && !Common::isDigit(fileName[j]); j++)
+ ;
+
+ const char *trackIDString = fileName.c_str() + j;
+ char *endPtr = nullptr;
+ long trackID = strtol(trackIDString, &endPtr, 10);
+
+ if (trackIDString != endPtr && trackID > 0 && trackID < UINT_MAX) {
+ _trackMap[trackID - 1] = drivePath + '/' + fileName;
+ } else {
+ warning("Invalid track file name: '%s'", fileName.c_str());
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+AudioCDManager *createMacOSXAudioCDManager() {
+ return new MacOSXAudioCDManager();
+}
+
+#endif // MACOSX
diff --git a/backends/audiocd/macosx/macosx-audiocd.h b/backends/audiocd/macosx/macosx-audiocd.h
new file mode 100644
index 0000000000..55b8c7b8c6
--- /dev/null
+++ b/backends/audiocd/macosx/macosx-audiocd.h
@@ -0,0 +1,61 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifndef BACKENDS_AUDIOCD_MACOSX_H
+#define BACKENDS_AUDIOCD_MACOSX_H
+
+#include "common/scummsys.h"
+
+#ifdef MACOSX
+
+class AudioCDManager;
+
+/**
+ * Create an audio CD manager for Mac OS X
+ */
+AudioCDManager *createMacOSXAudioCDManager();
+
+#endif
+
+#endif //
diff --git a/backends/audiocd/sdl/sdl-audiocd.cpp b/backends/audiocd/sdl/sdl-audiocd.cpp
index ff50c56af3..3558fb5671 100644
--- a/backends/audiocd/sdl/sdl-audiocd.cpp
+++ b/backends/audiocd/sdl/sdl-audiocd.cpp
@@ -43,10 +43,16 @@ SdlAudioCDManager::SdlAudioCDManager()
}
SdlAudioCDManager::~SdlAudioCDManager() {
- if (_cdrom) {
- SDL_CDStop(_cdrom);
- SDL_CDClose(_cdrom);
- }
+ close();
+}
+
+bool SdlAudioCDManager::open() {
+ close();
+
+ if (openRealCD())
+ return true;
+
+ return DefaultAudioCDManager::open();
}
bool SdlAudioCDManager::openCD(int drive) {
@@ -67,44 +73,69 @@ bool SdlAudioCDManager::openCD(int drive) {
return (_cdrom != NULL);
}
-void SdlAudioCDManager::stopCD() {
+void SdlAudioCDManager::close() {
+ DefaultAudioCDManager::close();
+
+ if (_cdrom) {
+ SDL_CDStop(_cdrom);
+ SDL_CDClose(_cdrom);
+ _cdrom = 0;
+ }
+}
+
+void SdlAudioCDManager::stop() {
+ DefaultAudioCDManager::stop();
+
// Stop CD Audio in 1/10th of a second
_cdStopTime = SDL_GetTicks() + 100;
_cdNumLoops = 0;
}
-void SdlAudioCDManager::playCD(int track, int num_loops, int start_frame, int duration) {
- if (!num_loops && !start_frame)
- return;
+bool SdlAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
+ // Prefer emulation
+ if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
+ return true;
- if (!_cdrom)
- return;
+ // If we're set to only emulate, or have no CD, return here
+ if (onlyEmulate || !_cdrom)
+ return false;
+ if (!numLoops && !startFrame)
+ return false;
+
+ // FIXME: Explain this.
if (duration > 0)
duration += 5;
_cdTrack = track;
- _cdNumLoops = num_loops;
- _cdStartFrame = start_frame;
+ _cdNumLoops = numLoops;
+ _cdStartFrame = startFrame;
SDL_CDStatus(_cdrom);
- if (start_frame == 0 && duration == 0)
+ if (startFrame == 0 && duration == 0)
SDL_CDPlayTracks(_cdrom, track, 0, 1, 0);
else
- SDL_CDPlayTracks(_cdrom, track, start_frame, 0, duration);
+ SDL_CDPlayTracks(_cdrom, track, startFrame, 0, duration);
_cdDuration = duration;
_cdStopTime = 0;
_cdEndTime = SDL_GetTicks() + _cdrom->track[track].length * 1000 / CD_FPS;
+
+ return true;
}
-bool SdlAudioCDManager::pollCD() const {
+bool SdlAudioCDManager::isPlaying() const {
+ if (DefaultAudioCDManager::isPlaying())
+ return true;
+
if (!_cdrom)
return false;
return (_cdNumLoops != 0 && (SDL_GetTicks() < _cdEndTime || SDL_CDStatus(_cdrom) == CD_PLAYING));
}
-void SdlAudioCDManager::updateCD() {
+void SdlAudioCDManager::update() {
+ DefaultAudioCDManager::update();
+
if (!_cdrom)
return;
diff --git a/backends/audiocd/sdl/sdl-audiocd.h b/backends/audiocd/sdl/sdl-audiocd.h
index bfad7b6805..91895dac99 100644
--- a/backends/audiocd/sdl/sdl-audiocd.h
+++ b/backends/audiocd/sdl/sdl-audiocd.h
@@ -37,12 +37,15 @@ public:
SdlAudioCDManager();
virtual ~SdlAudioCDManager();
+ virtual bool open();
+ virtual void close();
+ virtual bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
+ virtual void stop();
+ virtual bool isPlaying() const;
+ virtual void update();
+
protected:
virtual bool openCD(int drive);
- virtual void updateCD();
- virtual bool pollCD() const;
- virtual void playCD(int track, int num_loops, int start_frame, int duration);
- virtual void stopCD();
SDL_CD *_cdrom;
int _cdTrack, _cdNumLoops, _cdStartFrame, _cdDuration;
diff --git a/backends/audiocd/win32/msvc/ntddcdrm.h b/backends/audiocd/win32/msvc/ntddcdrm.h
new file mode 100644
index 0000000000..18527e2675
--- /dev/null
+++ b/backends/audiocd/win32/msvc/ntddcdrm.h
@@ -0,0 +1,362 @@
+/**
+ * @file ntddcdrm.h
+ * Copyright 2012, 2013 MinGW.org project
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ */
+/* Created by Casper S. Hornstrup <chorns@users.sourceforge.net> */
+#ifndef __NTDDCDRM_H
+#define __NTDDCDRM_H
+#if 0 // Added to make MSVC happy.
+#pragma GCC system_header
+#include <_mingw.h>
+#endif
+
+/*
+ * CDROM IOCTL interface.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 0 // Added to make MSVC happy.
+#include "ntddk.h"
+#include "ntddstor.h"
+#endif
+
+#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+
+#define IOCTL_CDROM_CHECK_VERIFY \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_FIND_NEW_DEVICES \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_CONTROL \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_DRIVE_GEOMETRY \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_LAST_SESSION \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_GET_VOLUME \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_PAUSE_AUDIO \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_PLAY_AUDIO_MSF \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_RAW_READ \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_READ_Q_CHANNEL \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_READ_TOC \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_READ_TOC_EX \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_RESUME_AUDIO \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_SEEK_AUDIO_MSF \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_SET_VOLUME \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_SIMBAD \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_CDROM_STOP_AUDIO \
+ CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+
+#define MAXIMUM_NUMBER_TRACKS 100
+#define MAXIMUM_CDROM_SIZE 804
+#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2
+
+typedef struct _TRACK_DATA {
+ UCHAR Reserved;
+ UCHAR Control : 4;
+ UCHAR Adr : 4;
+ UCHAR TrackNumber;
+ UCHAR Reserved1;
+ UCHAR Address[4];
+} TRACK_DATA, *PTRACK_DATA;
+
+/* CDROM_DISK_DATA.DiskData flags */
+#define CDROM_DISK_AUDIO_TRACK 0x00000001
+#define CDROM_DISK_DATA_TRACK 0x00000002
+
+typedef struct _CDROM_DISK_DATA {
+ ULONG DiskData;
+} CDROM_DISK_DATA, *PCDROM_DISK_DATA;
+
+typedef struct _CDROM_PLAY_AUDIO_MSF {
+ UCHAR StartingM;
+ UCHAR StartingS;
+ UCHAR StartingF;
+ UCHAR EndingM;
+ UCHAR EndingS;
+ UCHAR EndingF;
+} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF;
+
+/* CDROM_READ_TOC_EX.Format constants */
+#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00
+#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01
+#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02
+#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03
+#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04
+#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05
+
+typedef struct _CDROM_READ_TOC_EX {
+ UCHAR Format : 4;
+ UCHAR Reserved1 : 3;
+ UCHAR Msf : 1;
+ UCHAR SessionTrack;
+ UCHAR Reserved2;
+ UCHAR Reserved3;
+} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;
+
+typedef struct _CDROM_SEEK_AUDIO_MSF {
+ UCHAR M;
+ UCHAR S;
+ UCHAR F;
+} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF;
+
+/* CDROM_SUB_Q_DATA_FORMAT.Format constants */
+#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00
+#define IOCTL_CDROM_CURRENT_POSITION 0x01
+#define IOCTL_CDROM_MEDIA_CATALOG 0x02
+#define IOCTL_CDROM_TRACK_ISRC 0x03
+
+typedef struct _CDROM_SUB_Q_DATA_FORMAT {
+ UCHAR Format;
+ UCHAR Track;
+} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;
+
+typedef struct _CDROM_TOC {
+ UCHAR Length[2];
+ UCHAR FirstTrack;
+ UCHAR LastTrack;
+ TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS];
+} CDROM_TOC, *PCDROM_TOC;
+
+#define CDROM_TOC_SIZE sizeof(CDROM_TOC)
+
+typedef struct _CDROM_TOC_ATIP_DATA_BLOCK {
+ UCHAR CdrwReferenceSpeed : 3;
+ UCHAR Reserved3 : 1;
+ UCHAR WritePower : 3;
+ UCHAR True1 : 1;
+ UCHAR Reserved4 : 6;
+ UCHAR UnrestrictedUse : 1;
+ UCHAR Reserved5 : 1;
+ UCHAR A3Valid : 1;
+ UCHAR A2Valid : 1;
+ UCHAR A1Valid : 1;
+ UCHAR Reserved6 : 3;
+ UCHAR IsCdrw : 1;
+ UCHAR True2 : 1;
+ UCHAR Reserved7;
+ UCHAR LeadInMsf[3];
+ UCHAR Reserved8;
+ UCHAR LeadOutMsf[3];
+ UCHAR Reserved9;
+ UCHAR A1Values[3];
+ UCHAR Reserved10;
+ UCHAR A2Values[3];
+ UCHAR Reserved11;
+ UCHAR A3Values[3];
+ UCHAR Reserved12;
+} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK;
+
+#if 0 // Added to make MSVC happy.
+typedef struct _CDROM_TOC_ATIP_DATA {
+ UCHAR Length[2];
+ UCHAR Reserved1;
+ UCHAR Reserved2;
+ CDROM_TOC_ATIP_DATA_BLOCK Descriptors[0];
+ CDROM_TOC_ATIP_DATA_BLOCK Descriptors[1];
+} CDROM_TOC_ATIP_DATA, *PCDROM_TOC_ATIP_DATA;
+#endif
+
+/* CDROM_TOC_CD_TEXT_DATA_BLOCK.PackType constants */
+#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80
+#define CDROM_CD_TEXT_PACK_PERFORMER 0x81
+#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82
+#define CDROM_CD_TEXT_PACK_COMPOSER 0x83
+#define CDROM_CD_TEXT_PACK_ARRANGER 0x84
+#define CDROM_CD_TEXT_PACK_MESSAGES 0x85
+#define CDROM_CD_TEXT_PACK_DISC_ID 0x86
+#define CDROM_CD_TEXT_PACK_GENRE 0x87
+#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88
+#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89
+#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e
+#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f
+
+#if 0 // Added to make MSVC happy.
+typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK {
+ UCHAR PackType;
+ UCHAR TrackNumber : 7;
+ UCHAR ExtensionFlag : 1;
+ UCHAR SequenceNumber;
+ UCHAR CharacterPosition : 4;
+ UCHAR BlockNumber : 3;
+ UCHAR Unicode : 1;
+ _ANONYMOUS_UNION union {
+ UCHAR Text[12];
+ WCHAR WText[6];
+ } DUMMYUNIONNAME;
+ UCHAR CRC[2];
+} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;
+
+typedef struct _CDROM_TOC_CD_TEXT_DATA {
+ UCHAR Length[2];
+ UCHAR Reserved1;
+ UCHAR Reserved2;
+ CDROM_TOC_CD_TEXT_DATA_BLOCK Descriptors[0];
+} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA;
+#endif
+
+/* CDROM_TOC_FULL_TOC_DATA_BLOCK.Adr constants */
+#define ADR_NO_MODE_INFORMATION 0x0
+#define ADR_ENCODES_CURRENT_POSITION 0x1
+#define ADR_ENCODES_MEDIA_CATALOG 0x2
+#define ADR_ENCODES_ISRC 0x3
+
+typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK {
+ UCHAR SessionNumber;
+ UCHAR Control : 4;
+ UCHAR Adr : 4;
+ UCHAR Reserved1;
+ UCHAR Point;
+ UCHAR MsfExtra[3];
+ UCHAR Zero;
+ UCHAR Msf[3];
+} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK;
+
+#if 0 // Added to make MSVC happy.
+typedef struct _CDROM_TOC_FULL_TOC_DATA {
+ UCHAR Length[2];
+ UCHAR FirstCompleteSession;
+ UCHAR LastCompleteSession;
+ CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0];
+} CDROM_TOC_FULL_TOC_DATA, *PCDROM_TOC_FULL_TOC_DATA;
+
+typedef struct _CDROM_TOC_PMA_DATA {
+ UCHAR Length[2];
+ UCHAR Reserved1;
+ UCHAR Reserved2;
+ CDROM_TOC_FULL_TOC_DATA_BLOCK Descriptors[0];
+} CDROM_TOC_PMA_DATA, *PCDROM_TOC_PMA_DATA;
+#endif
+
+/* SUB_Q_HEADER.AudioStatus constants */
+#define AUDIO_STATUS_NOT_SUPPORTED 0x00
+#define AUDIO_STATUS_IN_PROGRESS 0x11
+#define AUDIO_STATUS_PAUSED 0x12
+#define AUDIO_STATUS_PLAY_COMPLETE 0x13
+#define AUDIO_STATUS_PLAY_ERROR 0x14
+#define AUDIO_STATUS_NO_STATUS 0x15
+
+typedef struct _SUB_Q_HEADER {
+ UCHAR Reserved;
+ UCHAR AudioStatus;
+ UCHAR DataLength[2];
+} SUB_Q_HEADER, *PSUB_Q_HEADER;
+
+typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
+ SUB_Q_HEADER Header;
+ UCHAR FormatCode;
+ UCHAR Reserved[3];
+ UCHAR Reserved1 : 7;
+ UCHAR Mcval :1;
+ UCHAR MediaCatalog[15];
+} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;
+
+typedef struct _SUB_Q_TRACK_ISRC {
+ SUB_Q_HEADER Header;
+ UCHAR FormatCode;
+ UCHAR Reserved0;
+ UCHAR Track;
+ UCHAR Reserved1;
+ UCHAR Reserved2 : 7;
+ UCHAR Tcval : 1;
+ UCHAR TrackIsrc[15];
+} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC;
+
+typedef struct _SUB_Q_CURRENT_POSITION {
+ SUB_Q_HEADER Header;
+ UCHAR FormatCode;
+ UCHAR Control : 4;
+ UCHAR ADR : 4;
+ UCHAR TrackNumber;
+ UCHAR IndexNumber;
+ UCHAR AbsoluteAddress[4];
+ UCHAR TrackRelativeAddress[4];
+} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION;
+
+typedef union _SUB_Q_CHANNEL_DATA {
+ SUB_Q_CURRENT_POSITION CurrentPosition;
+ SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog;
+ SUB_Q_TRACK_ISRC TrackIsrc;
+} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA;
+
+/* CDROM_AUDIO_CONTROL.LbaFormat constants */
+#define AUDIO_WITH_PREEMPHASIS 0x1
+#define DIGITAL_COPY_PERMITTED 0x2
+#define AUDIO_DATA_TRACK 0x4
+#define TWO_FOUR_CHANNEL_AUDIO 0x8
+
+typedef struct _CDROM_AUDIO_CONTROL {
+ UCHAR LbaFormat;
+ USHORT LogicalBlocksPerSecond;
+} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL;
+
+typedef struct _VOLUME_CONTROL {
+ UCHAR PortVolume[4];
+} VOLUME_CONTROL, *PVOLUME_CONTROL;
+
+typedef enum _TRACK_MODE_TYPE {
+ YellowMode2,
+ XAForm2,
+ CDDA
+} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
+
+typedef struct __RAW_READ_INFO {
+ LARGE_INTEGER DiskOffset;
+ ULONG SectorCount;
+ TRACK_MODE_TYPE TrackMode;
+} RAW_READ_INFO, *PRAW_READ_INFO;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __NTDDCDRM_H */
diff --git a/backends/audiocd/win32/win32-audiocd.cpp b/backends/audiocd/win32/win32-audiocd.cpp
new file mode 100644
index 0000000000..6c057efdb7
--- /dev/null
+++ b/backends/audiocd/win32/win32-audiocd.cpp
@@ -0,0 +1,388 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifdef WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef ARRAYSIZE // winnt.h defines ARRAYSIZE, but we want our own one...
+
+#include "backends/audiocd/win32/win32-audiocd.h"
+
+#include "audio/audiostream.h"
+#include "backends/audiocd/audiocd-stream.h"
+#include "backends/audiocd/default/default-audiocd.h"
+#include "common/array.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/mutex.h"
+#include "common/queue.h"
+#include "common/str.h"
+#include "common/timer.h"
+
+#include <winioctl.h>
+#if _MSC_VER < 1900
+// WORKAROUND: Older versions of MSVC might not supply DDK headers by default.
+// Visual Studio 2015 contains the required headers. We use a compatability
+// header from MinGW's w32api for all older versions.
+// TODO: Limit this to the Visual Studio versions which actually require this.
+#include "msvc/ntddcdrm.h"
+#elif defined(__MINGW32__) && !defined(__MINGW64__)
+// Classic MinGW uses non standard paths for DDK headers.
+#include <ddk/ntddcdrm.h>
+#else
+#include <ntddcdrm.h>
+#endif
+
+class Win32AudioCDStream : public AudioCDStream {
+public:
+ Win32AudioCDStream(HANDLE handle, const TRACK_DATA &startEntry, const TRACK_DATA &endEntry);
+ ~Win32AudioCDStream();
+
+protected:
+ uint getStartFrame() const;
+ uint getEndFrame() const;
+ bool readFrame(int frame, int16 *buffer);
+
+private:
+ HANDLE _driveHandle;
+ const TRACK_DATA &_startEntry, &_endEntry;
+
+ enum {
+ // The CD-ROM pre-gap is 2s
+ kPreGapFrames = kFramesPerSecond * 2
+ };
+
+ static int getFrameCount(const TRACK_DATA &data) {
+ int time = data.Address[1];
+ time *= kSecondsPerMinute;
+ time += data.Address[2];
+ time *= kFramesPerSecond;
+ time += data.Address[3];
+ return time;
+ }
+};
+
+Win32AudioCDStream::Win32AudioCDStream(HANDLE handle, const TRACK_DATA &startEntry, const TRACK_DATA &endEntry) :
+ _driveHandle(handle), _startEntry(startEntry), _endEntry(endEntry) {
+ // We fill the buffer here already to prevent any out of sync issues due
+ // to the CD not yet having spun up.
+ startTimer(true);
+}
+
+Win32AudioCDStream::~Win32AudioCDStream() {
+ stopTimer();
+}
+
+uint Win32AudioCDStream::getStartFrame() const {
+ return getFrameCount(_startEntry);
+}
+
+uint Win32AudioCDStream::getEndFrame() const {
+ return getFrameCount(_endEntry);
+}
+
+bool Win32AudioCDStream::readFrame(int frame, int16 *buffer) {
+ // Request to read that frame
+ RAW_READ_INFO readAudio;
+ memset(&readAudio, 0, sizeof(readAudio));
+ readAudio.DiskOffset.QuadPart = (frame - kPreGapFrames) * 2048;
+ readAudio.SectorCount = 1;
+ readAudio.TrackMode = CDDA;
+
+ DWORD bytesReturned;
+ return DeviceIoControl(
+ _driveHandle,
+ IOCTL_CDROM_RAW_READ,
+ &readAudio,
+ sizeof(readAudio),
+ buffer,
+ kBytesPerFrame,
+ &bytesReturned,
+ NULL);
+}
+
+
+class Win32AudioCDManager : public DefaultAudioCDManager {
+public:
+ Win32AudioCDManager();
+ ~Win32AudioCDManager();
+
+ bool open();
+ void close();
+ bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
+
+protected:
+ bool openCD(int drive);
+ bool openCD(const Common::String &drive);
+
+private:
+ bool loadTOC();
+
+ typedef Common::Array<char> DriveList;
+ DriveList detectDrives();
+ bool tryAddDrive(char drive, DriveList &drives);
+
+ HANDLE _driveHandle;
+ int _firstTrack, _lastTrack;
+ Common::Array<TRACK_DATA> _tocEntries;
+};
+
+Win32AudioCDManager::Win32AudioCDManager() {
+ _driveHandle = INVALID_HANDLE_VALUE;
+ _firstTrack = _lastTrack = 0;
+}
+
+Win32AudioCDManager::~Win32AudioCDManager() {
+ close();
+}
+
+bool Win32AudioCDManager::open() {
+ close();
+
+ if (openRealCD())
+ return true;
+
+ return DefaultAudioCDManager::open();
+}
+
+bool Win32AudioCDManager::openCD(int drive) {
+ // Fetch the drive list
+ DriveList drives = detectDrives();
+ if (drive >= (int)drives.size())
+ return false;
+
+ debug(1, "Opening CD drive %c:\\", drives[drive]);
+
+ // Construct the drive path and try to open it
+ Common::String drivePath = Common::String::format("\\\\.\\%c:", drives[drive]);
+ _driveHandle = CreateFileA(drivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (_driveHandle == INVALID_HANDLE_VALUE) {
+ warning("Failed to open drive %c:\\, error %d", drives[drive], (int)GetLastError());
+ return false;
+ }
+
+ if (!loadTOC()) {
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+bool Win32AudioCDManager::openCD(const Common::String &drive) {
+ // Just some bounds checking
+ if (drive.empty() || drive.size() > 3)
+ return false;
+
+ if (!Common::isAlpha(drive[0]) || drive[1] != ':')
+ return false;
+
+ if (drive[2] != 0 && drive[2] != '\\')
+ return false;
+
+ DriveList drives;
+ if (!tryAddDrive(toupper(drive[0]), drives))
+ return false;
+
+ // Construct the drive path and try to open it
+ Common::String drivePath = Common::String::format("\\\\.\\%c:", drives[0]);
+ _driveHandle = CreateFileA(drivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (_driveHandle == INVALID_HANDLE_VALUE) {
+ warning("Failed to open drive %c:\\, error %d", drives[0], (int)GetLastError());
+ return false;
+ }
+
+ if (!loadTOC()) {
+ close();
+ return false;
+ }
+
+ return true;
+}
+
+void Win32AudioCDManager::close() {
+ DefaultAudioCDManager::close();
+
+ if (_driveHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(_driveHandle);
+ _driveHandle = INVALID_HANDLE_VALUE;
+ }
+
+ _firstTrack = _lastTrack = 0;
+ _tocEntries.clear();
+}
+
+bool Win32AudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
+ // Prefer emulation
+ if (DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate))
+ return true;
+
+ // If we're set to only emulate, or have no CD drive, return here
+ if (onlyEmulate || _driveHandle == INVALID_HANDLE_VALUE)
+ return false;
+
+ // HACK: For now, just assume that track number is right
+ // That only works because ScummVM uses the wrong track number anyway
+
+ if (track >= (int)_tocEntries.size() - 1) {
+ warning("No such track %d", track);
+ return false;
+ }
+
+ // Bail if the track isn't an audio track
+ if ((_tocEntries[track].Control & 0x04) != 0) {
+ warning("Track %d is not audio", track);
+ return false;
+ }
+
+ // Create the AudioStream and play it
+ debug(1, "Playing CD track %d", track);
+
+ Audio::SeekableAudioStream *audioStream = new Win32AudioCDStream(_driveHandle, _tocEntries[track], _tocEntries[track + 1]);
+
+ Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
+ Audio::Timestamp end = (duration == 0) ? audioStream->getLength() : Audio::Timestamp(0, startFrame + duration, 75);
+
+ // Fake emulation since we're really playing an AudioStream
+ _emulating = true;
+
+ _mixer->playStream(
+ Audio::Mixer::kMusicSoundType,
+ &_handle,
+ Audio::makeLoopingAudioStream(audioStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops),
+ -1,
+ _cd.volume,
+ _cd.balance,
+ DisposeAfterUse::YES,
+ true);
+ return true;
+}
+
+bool Win32AudioCDManager::loadTOC() {
+ CDROM_READ_TOC_EX tocRequest;
+ memset(&tocRequest, 0, sizeof(tocRequest));
+ tocRequest.Format = CDROM_READ_TOC_EX_FORMAT_TOC;
+ tocRequest.Msf = 1;
+ tocRequest.SessionTrack = 0;
+
+ DWORD bytesReturned;
+ CDROM_TOC tocData;
+ bool result = DeviceIoControl(
+ _driveHandle,
+ IOCTL_CDROM_READ_TOC_EX,
+ &tocRequest,
+ sizeof(tocRequest),
+ &tocData,
+ sizeof(tocData),
+ &bytesReturned,
+ NULL);
+ if (!result) {
+ debug("Failed to query the CD TOC: %d", (int)GetLastError());
+ return false;
+ }
+
+ _firstTrack = tocData.FirstTrack;
+ _lastTrack = tocData.LastTrack;
+#if 0
+ debug("First Track: %d", tocData.FirstTrack);
+ debug("Last Track: %d", tocData.LastTrack);
+#endif
+
+ for (uint32 i = 0; i < (bytesReturned - 4) / sizeof(TRACK_DATA); i++)
+ _tocEntries.push_back(tocData.TrackData[i]);
+
+#if 0
+ for (uint32 i = 0; i < _tocEntries.size(); i++) {
+ const TRACK_DATA &entry = _tocEntries[i];
+ debug("Entry:");
+ debug("\tTrack: %d", entry.TrackNumber);
+ debug("\tAdr: %d", entry.Adr);
+ debug("\tCtrl: %d", entry.Control);
+ debug("\tMSF: %d:%d:%d\n", entry.Address[1], entry.Address[2], entry.Address[3]);
+ }
+#endif
+
+ return true;
+}
+
+Win32AudioCDManager::DriveList Win32AudioCDManager::detectDrives() {
+ DriveList drives;
+
+ // Try to get the game path's drive
+ char gameDrive = 0;
+ if (ConfMan.hasKey("path")) {
+ Common::String gamePath = ConfMan.get("path");
+ char fullPath[MAX_PATH];
+ DWORD result = GetFullPathNameA(gamePath.c_str(), sizeof(fullPath), fullPath, 0);
+
+ if (result > 0 && result < sizeof(fullPath) && Common::isAlpha(fullPath[0]) && fullPath[1] == ':' && tryAddDrive(toupper(fullPath[0]), drives))
+ gameDrive = drives[0];
+ }
+
+ // Try adding the rest of the drives
+ for (char drive = 'A'; drive <= 'Z'; drive++)
+ if (drive != gameDrive)
+ tryAddDrive(drive, drives);
+
+ return drives;
+}
+
+bool Win32AudioCDManager::tryAddDrive(char drive, DriveList &drives) {
+ Common::String drivePath = Common::String::format("%c:\\", drive);
+
+ // Ensure it's an actual CD drive
+ if (GetDriveTypeA(drivePath.c_str()) != DRIVE_CDROM)
+ return false;
+
+ debug(2, "Detected drive %c:\\ as a CD drive", drive);
+ drives.push_back(drive);
+ return true;
+}
+
+AudioCDManager *createWin32AudioCDManager() {
+ return new Win32AudioCDManager();
+}
+
+#endif // WIN32 \ No newline at end of file
diff --git a/backends/audiocd/win32/win32-audiocd.h b/backends/audiocd/win32/win32-audiocd.h
new file mode 100644
index 0000000000..0c103641ef
--- /dev/null
+++ b/backends/audiocd/win32/win32-audiocd.h
@@ -0,0 +1,60 @@
+/* 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.
+ *
+ * Original license header:
+ *
+ * Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifndef BACKENDS_AUDIOCD_WIN32_H
+#define BACKENDS_AUDIOCD_WIN32_H
+
+#ifdef WIN32
+
+class AudioCDManager;
+
+/**
+ * Create an AudioCDManager using the Win32 API
+ */
+AudioCDManager *createWin32AudioCDManager();
+
+#endif
+
+#endif
+
diff --git a/backends/events/androidsdl/androidsdl-events.cpp b/backends/events/androidsdl/androidsdl-events.cpp
new file mode 100644
index 0000000000..bd8045ec62
--- /dev/null
+++ b/backends/events/androidsdl/androidsdl-events.cpp
@@ -0,0 +1,84 @@
+/* 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.
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(ANDROIDSDL)
+
+#include "backends/events/androidsdl/androidsdl-events.h"
+#include "backends/platform/androidsdl/androidsdl-sdl.h"
+#include <SDL_screenkeyboard.h>
+
+bool AndroidSdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
+ if (ev.button.button == SDL_BUTTON_LEFT)
+ event.type = Common::EVENT_LBUTTONDOWN;
+ else if (ev.button.button == SDL_BUTTON_RIGHT)
+ event.type = Common::EVENT_RBUTTONDOWN;
+#if defined(SDL_BUTTON_WHEELUP) && defined(SDL_BUTTON_WHEELDOWN)
+ else if (ev.button.button == SDL_BUTTON_WHEELUP)
+ event.type = Common::EVENT_WHEELUP;
+ else if (ev.button.button == SDL_BUTTON_WHEELDOWN)
+ event.type = Common::EVENT_WHEELDOWN;
+#endif
+#if defined(SDL_BUTTON_MIDDLE)
+ else if (ev.button.button == SDL_BUTTON_MIDDLE) {
+ event.type = Common::EVENT_MBUTTONDOWN;
+
+ static int show_onscreen=0;
+ if (show_onscreen==0) {
+ SDL_ANDROID_SetScreenKeyboardShown(0);
+ show_onscreen++;
+ }
+ else if (show_onscreen==1) {
+ SDL_ANDROID_SetScreenKeyboardShown(1);
+ show_onscreen++;
+ }
+ if (show_onscreen==2)
+ show_onscreen=0;
+ }
+#endif
+ else
+ return false;
+
+ processMouseEvent(event, ev.button.x, ev.button.y);
+
+ return true;
+}
+
+bool AndroidSdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
+ if (false) {}
+
+ if (ev.key.keysym.sym == SDLK_LCTRL) {
+ ev.key.keysym.sym = SDLK_F5;
+ } else {
+ // Let the events fall through if we didn't change them, this may not be the best way to
+ // set it up, but i'm not sure how sdl would like it if we let if fall through then redid it though.
+ // and yes i have an huge terminal size so i dont wrap soon enough.
+ event.type = Common::EVENT_KEYDOWN;
+ event.kbd.keycode = (Common::KeyCode)ev.key.keysym.sym;
+ event.kbd.ascii = mapKey(ev.key.keysym.sym, ev.key.keysym.mod, ev.key.keysym.unicode);
+ }
+
+ return false;
+}
+
+#endif
diff --git a/backends/events/androidsdl/androidsdl-events.h b/backends/events/androidsdl/androidsdl-events.h
new file mode 100644
index 0000000000..bca712e579
--- /dev/null
+++ b/backends/events/androidsdl/androidsdl-events.h
@@ -0,0 +1,37 @@
+/* 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.
+ *
+ */
+
+#if !defined(BACKEND_EVENTS_SDL_ANDROIDSDL_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
+#define BACKEND_EVENTS_SDL_ANDROIDSDL_H
+
+#include "backends/events/sdl/sdl-events.h"
+
+/**
+ * SDL events manager for ANDROIDSDL
+ */
+class AndroidSdlEventSource : public SdlEventSource {
+protected:
+ virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event);
+ virtual bool remapKey(SDL_Event &ev, Common::Event &event);
+};
+
+#endif
diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp
index 7b56a0a955..00e2f25cbc 100644
--- a/backends/events/sdl/sdl-events.cpp
+++ b/backends/events/sdl/sdl-events.cpp
@@ -872,6 +872,21 @@ uint32 SdlEventSource::obtainUnicode(const SDL_keysym keySym) {
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_Event events[2];
+ // Update the event queue here to give SDL a chance to insert TEXTINPUT
+ // events for KEYDOWN events. Otherwise we have a high chance that on
+ // Windows the TEXTINPUT event is not in the event queue at this point.
+ // In this case we will get two events with ascii values due to mapKey
+ // and dispatchSDLEvent. This results in nasty double input of characters
+ // in the GUI.
+ //
+ // FIXME: This is all a bit fragile because in mapKey we derive the ascii
+ // value from the key code if no unicode value is given. This is legacy
+ // behavior and should be removed anyway. If that is removed, we might not
+ // even need to do this peeking here but instead can rely on the
+ // SDL_TEXTINPUT case in dispatchSDLEvent to introduce keydown/keyup with
+ // proper ASCII values (but with KEYCODE_INVALID as keycode).
+ SDL_PumpEvents();
+
// In SDL2, the unicode field has been removed from the keysym struct.
// Instead a SDL_TEXTINPUT event is generated on key combinations that
// generates unicode.
diff --git a/backends/graphics/androidsdl/androidsdl-graphics.cpp b/backends/graphics/androidsdl/androidsdl-graphics.cpp
new file mode 100644
index 0000000000..23a1a86dd6
--- /dev/null
+++ b/backends/graphics/androidsdl/androidsdl-graphics.cpp
@@ -0,0 +1,42 @@
+/* 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.
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(ANDROIDSDL)
+
+#include "backends/graphics/androidsdl/androidsdl-graphics.h"
+#include "backends/events/androidsdl/androidsdl-events.h"
+#include "common/mutex.h"
+#include "common/textconsole.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/scaler.h"
+#include "graphics/scaler/aspect.h"
+#include "graphics/scaler/downscaler.h"
+#include "graphics/surface.h"
+
+AndroidSdlGraphicsManager::AndroidSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window)
+ : SurfaceSdlGraphicsManager(sdlEventSource, window) {
+}
+
+#endif
diff --git a/backends/graphics/androidsdl/androidsdl-graphics.h b/backends/graphics/androidsdl/androidsdl-graphics.h
new file mode 100644
index 0000000000..b7ca7c1de8
--- /dev/null
+++ b/backends/graphics/androidsdl/androidsdl-graphics.h
@@ -0,0 +1,34 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_SDL_ANDROIDSDL_H
+#define BACKENDS_GRAPHICS_SDL_ANDROIDSDL_H
+
+#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
+
+class AndroidSdlGraphicsManager : public SurfaceSdlGraphicsManager {
+public:
+ AndroidSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window);
+
+};
+
+#endif
diff --git a/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp b/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp
index 0b9cc0c7e8..7a248f1859 100644
--- a/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp
+++ b/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp
@@ -35,6 +35,10 @@ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = {
{0, 0, 0}
};
+#ifndef USE_SCALERS
+#define DownscaleAllByHalf 0
+#endif
+
DINGUXSdlGraphicsManager::DINGUXSdlGraphicsManager(SdlEventSource *boss, SdlWindow *window)
: SurfaceSdlGraphicsManager(boss, window) {
}
@@ -61,9 +65,11 @@ bool DINGUXSdlGraphicsManager::setGraphicsMode(int mode) {
case GFX_NORMAL:
newScaleFactor = 1;
break;
+#ifdef USE_SCALERS
case GFX_HALF:
newScaleFactor = 1;
break;
+#endif
default:
warning("unknown gfx mode %d", mode);
return false;
@@ -89,9 +95,11 @@ void DINGUXSdlGraphicsManager::setGraphicsModeIntern() {
case GFX_NORMAL:
newScalerProc = Normal1x;
break;
+#ifdef USE_SCALERS
case GFX_HALF:
newScalerProc = DownscaleAllByHalf;
break;
+#endif
default:
error("Unknown gfx mode %d", _videoMode.mode);
diff --git a/backends/graphics/opengl/context.cpp b/backends/graphics/opengl/context.cpp
new file mode 100644
index 0000000000..a7f640d37e
--- /dev/null
+++ b/backends/graphics/opengl/context.cpp
@@ -0,0 +1,182 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/opengl-sys.h"
+#include "backends/graphics/opengl/opengl-graphics.h"
+#include "backends/graphics/opengl/shader.h"
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+#include "backends/graphics/opengl/framebuffer.h"
+
+#include "common/tokenizer.h"
+#include "common/debug.h"
+
+namespace OpenGL {
+
+void Context::reset() {
+ maxTextureSize = 0;
+
+ NPOTSupported = false;
+ shadersSupported = false;
+ multitextureSupported = false;
+ framebufferObjectSupported = false;
+
+#define GL_FUNC_DEF(ret, name, param) name = nullptr;
+#include "backends/graphics/opengl/opengl-func.h"
+#undef GL_FUNC_DEF
+
+ activePipeline = nullptr;
+}
+
+Pipeline *Context::setPipeline(Pipeline *pipeline) {
+ Pipeline *oldPipeline = activePipeline;
+ if (oldPipeline) {
+ oldPipeline->deactivate();
+ }
+
+ activePipeline = pipeline;
+ if (activePipeline) {
+ activePipeline->activate();
+ }
+
+ return oldPipeline;
+}
+
+Context g_context;
+
+void OpenGLGraphicsManager::setContextType(ContextType type) {
+#if USE_FORCED_GL
+ type = kContextGL;
+#elif USE_FORCED_GLES
+ type = kContextGLES;
+#elif USE_FORCED_GLES2
+ type = kContextGLES2;
+#endif
+
+ g_context.type = type;
+}
+
+void OpenGLGraphicsManager::initializeGLContext() {
+ // Initialize default state.
+ g_context.reset();
+
+ // Load all functions.
+ // We use horrible trickery to silence C++ compilers.
+ // See backends/plugins/sdl/sdl-provider.cpp for more information.
+ assert(sizeof(void (*)()) == sizeof(void *));
+ void *fn = nullptr;
+
+#define LOAD_FUNC(name, loadName) \
+ fn = getProcAddress(#loadName); \
+ memcpy(&g_context.name, &fn, sizeof(fn))
+
+#define GL_EXT_FUNC_DEF(ret, name, param) LOAD_FUNC(name, name)
+
+#ifdef USE_BUILTIN_OPENGL
+#define GL_FUNC_DEF(ret, name, param) g_context.name = &name
+#define GL_FUNC_2_DEF GL_FUNC_DEF
+#else
+#define GL_FUNC_DEF GL_EXT_FUNC_DEF
+#define GL_FUNC_2_DEF(ret, name, extName, param) \
+ if (g_context.type == kContextGL) { \
+ LOAD_FUNC(name, extName); \
+ } else { \
+ LOAD_FUNC(name, name); \
+ }
+#endif
+#include "backends/graphics/opengl/opengl-func.h"
+#undef GL_FUNC_2_DEF
+#undef GL_FUNC_DEF
+#undef GL_EXT_FUNC_DEF
+#undef LOAD_FUNC
+
+ // Obtain maximum texture size.
+ GL_CALL(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_context.maxTextureSize));
+ debug(5, "OpenGL maximum texture size: %d", g_context.maxTextureSize);
+
+ const char *extString = (const char *)g_context.glGetString(GL_EXTENSIONS);
+ debug(5, "OpenGL extensions: %s", extString);
+
+ bool ARBShaderObjects = false;
+ bool ARBShadingLanguage100 = false;
+ bool ARBVertexShader = false;
+ bool ARBFragmentShader = false;
+
+ Common::StringTokenizer tokenizer(extString, " ");
+ while (!tokenizer.empty()) {
+ Common::String token = tokenizer.nextToken();
+
+ if (token == "GL_ARB_texture_non_power_of_two" || token == "GL_OES_texture_npot") {
+ g_context.NPOTSupported = true;
+ } else if (token == "GL_ARB_shader_objects") {
+ ARBShaderObjects = true;
+ } else if (token == "GL_ARB_shading_language_100") {
+ ARBShadingLanguage100 = true;
+ } else if (token == "GL_ARB_vertex_shader") {
+ ARBVertexShader = true;
+ } else if (token == "GL_ARB_fragment_shader") {
+ ARBFragmentShader = true;
+ } else if (token == "GL_ARB_multitexture") {
+ g_context.multitextureSupported = true;
+ } else if (token == "GL_EXT_framebuffer_object") {
+ g_context.framebufferObjectSupported = true;
+ }
+ }
+
+ if (g_context.type == kContextGLES2) {
+ // GLES2 always has (limited) NPOT support.
+ g_context.NPOTSupported = true;
+
+ // GLES2 always has shader support.
+ g_context.shadersSupported = true;
+
+ // GLES2 always has multi texture support.
+ g_context.multitextureSupported = true;
+
+ // GLES2 always has FBO support.
+ g_context.framebufferObjectSupported = true;
+ } else {
+ g_context.shadersSupported = ARBShaderObjects & ARBShadingLanguage100 & ARBVertexShader & ARBFragmentShader;
+ }
+
+ // Log context type.
+ switch (g_context.type) {
+ case kContextGL:
+ debug(5, "OpenGL: GL context initialized");
+ break;
+
+ case kContextGLES:
+ debug(5, "OpenGL: GLES context initialized");
+ break;
+
+ case kContextGLES2:
+ debug(5, "OpenGL: GLES2 context initialized");
+ break;
+ }
+
+ // Log features supported by GL context.
+ debug(5, "OpenGL: NPOT texture support: %d", g_context.NPOTSupported);
+ debug(5, "OpenGL: Shader support: %d", g_context.shadersSupported);
+ debug(5, "OpenGL: Multitexture support: %d", g_context.multitextureSupported);
+ debug(5, "OpenGL: FBO support: %d", g_context.framebufferObjectSupported);
+}
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/debug.cpp b/backends/graphics/opengl/debug.cpp
index d5d73fb5ec..c4319f5e36 100644
--- a/backends/graphics/opengl/debug.cpp
+++ b/backends/graphics/opengl/debug.cpp
@@ -54,7 +54,7 @@ Common::String getGLErrStr(GLenum error) {
void checkGLError(const char *expr, const char *file, int line) {
GLenum error;
- while ((error = glGetError()) != GL_NO_ERROR) {
+ while ((error = g_context.glGetError()) != GL_NO_ERROR) {
// We cannot use error here because we do not know whether we have a
// working screen or not.
warning("GL ERROR: %s on %s (%s:%d)", getGLErrStr(error).c_str(), expr, file, line);
diff --git a/backends/graphics/opengl/debug.h b/backends/graphics/opengl/debug.h
index ff6b678870..abaa6544dc 100644
--- a/backends/graphics/opengl/debug.h
+++ b/backends/graphics/opengl/debug.h
@@ -31,9 +31,9 @@ namespace OpenGL {
void checkGLError(const char *expr, const char *file, int line);
} // End of namespace OpenGL
-#define GLCALL(x) do { (x); OpenGL::checkGLError(#x, __FILE__, __LINE__); } while (false)
+#define GL_WRAP_DEBUG(call, name) do { (call); OpenGL::checkGLError(#name, __FILE__, __LINE__); } while (false)
#else
-#define GLCALL(x) do { (x); } while (false)
+#define GL_WRAP_DEBUG(call, name) do { (call); } while (false)
#endif
#endif
diff --git a/backends/graphics/opengl/framebuffer.cpp b/backends/graphics/opengl/framebuffer.cpp
new file mode 100644
index 0000000000..7191aab8bc
--- /dev/null
+++ b/backends/graphics/opengl/framebuffer.cpp
@@ -0,0 +1,259 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/framebuffer.h"
+#include "backends/graphics/opengl/texture.h"
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+
+namespace OpenGL {
+
+Framebuffer::Framebuffer()
+ : _viewport(), _projectionMatrix(), _isActive(false), _clearColor(),
+ _blendState(false), _scissorTestState(false), _scissorBox() {
+}
+
+void Framebuffer::activate() {
+ _isActive = true;
+
+ applyViewport();
+ applyProjectionMatrix();
+ applyClearColor();
+ applyBlendState();
+ applyScissorTestState();
+ applyScissorBox();
+
+ activateInternal();
+}
+
+void Framebuffer::deactivate() {
+ _isActive = false;
+
+ deactivateInternal();
+}
+
+void Framebuffer::setClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
+ _clearColor[0] = r;
+ _clearColor[1] = g;
+ _clearColor[2] = b;
+ _clearColor[3] = a;
+
+ // Directly apply changes when we are active.
+ if (isActive()) {
+ applyClearColor();
+ }
+}
+
+void Framebuffer::enableBlend(bool enable) {
+ _blendState = enable;
+
+ // Directly apply changes when we are active.
+ if (isActive()) {
+ applyBlendState();
+ }
+}
+
+void Framebuffer::enableScissorTest(bool enable) {
+ _scissorTestState = enable;
+
+ // Directly apply changes when we are active.
+ if (isActive()) {
+ applyScissorTestState();
+ }
+}
+
+void Framebuffer::setScissorBox(GLint x, GLint y, GLsizei w, GLsizei h) {
+ _scissorBox[0] = x;
+ _scissorBox[1] = y;
+ _scissorBox[2] = w;
+ _scissorBox[3] = h;
+
+ // Directly apply changes when we are active.
+ if (isActive()) {
+ applyScissorBox();
+ }
+}
+
+void Framebuffer::applyViewport() {
+ GL_CALL(glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]));
+}
+
+void Framebuffer::applyProjectionMatrix() {
+ g_context.getActivePipeline()->setProjectionMatrix(_projectionMatrix);
+}
+
+void Framebuffer::applyClearColor() {
+ GL_CALL(glClearColor(_clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]));
+}
+
+void Framebuffer::applyBlendState() {
+ if (_blendState) {
+ GL_CALL(glEnable(GL_BLEND));
+ } else {
+ GL_CALL(glDisable(GL_BLEND));
+ }
+}
+
+void Framebuffer::applyScissorTestState() {
+ if (_scissorTestState) {
+ GL_CALL(glEnable(GL_SCISSOR_TEST));
+ } else {
+ GL_CALL(glDisable(GL_SCISSOR_TEST));
+ }
+}
+
+void Framebuffer::applyScissorBox() {
+ GL_CALL(glScissor(_scissorBox[0], _scissorBox[1], _scissorBox[2], _scissorBox[3]));
+}
+
+//
+// Backbuffer implementation
+//
+
+void Backbuffer::activateInternal() {
+#if !USE_FORCED_GLES
+ if (g_context.framebufferObjectSupported) {
+ GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+ }
+#endif
+}
+
+void Backbuffer::setDimensions(uint width, uint height) {
+ // Set viewport dimensions.
+ _viewport[0] = 0;
+ _viewport[1] = 0;
+ _viewport[2] = width;
+ _viewport[3] = height;
+
+ // Setup orthogonal projection matrix.
+ _projectionMatrix[ 0] = 2.0f / width;
+ _projectionMatrix[ 1] = 0.0f;
+ _projectionMatrix[ 2] = 0.0f;
+ _projectionMatrix[ 3] = 0.0f;
+
+ _projectionMatrix[ 4] = 0.0f;
+ _projectionMatrix[ 5] = -2.0f / height;
+ _projectionMatrix[ 6] = 0.0f;
+ _projectionMatrix[ 7] = 0.0f;
+
+ _projectionMatrix[ 8] = 0.0f;
+ _projectionMatrix[ 9] = 0.0f;
+ _projectionMatrix[10] = 0.0f;
+ _projectionMatrix[11] = 0.0f;
+
+ _projectionMatrix[12] = -1.0f;
+ _projectionMatrix[13] = 1.0f;
+ _projectionMatrix[14] = 0.0f;
+ _projectionMatrix[15] = 1.0f;
+
+ // Directly apply changes when we are active.
+ if (isActive()) {
+ applyViewport();
+ applyProjectionMatrix();
+ }
+}
+
+//
+// Render to texture target implementation
+//
+
+#if !USE_FORCED_GLES
+TextureTarget::TextureTarget()
+ : _texture(new GLTexture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE)), _glFBO(0), _needUpdate(true) {
+}
+
+TextureTarget::~TextureTarget() {
+ delete _texture;
+ GL_CALL_SAFE(glDeleteFramebuffers, (1, &_glFBO));
+}
+
+void TextureTarget::activateInternal() {
+ // Allocate framebuffer object if necessary.
+ if (!_glFBO) {
+ GL_CALL(glGenFramebuffers(1, &_glFBO));
+ _needUpdate = true;
+ }
+
+ // Attach destination texture to FBO.
+ GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, _glFBO));
+
+ // If required attach texture to FBO.
+ if (_needUpdate) {
+ GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture->getGLTexture(), 0));
+ _needUpdate = false;
+ }
+}
+
+void TextureTarget::destroy() {
+ GL_CALL(glDeleteFramebuffers(1, &_glFBO));
+ _glFBO = 0;
+
+ _texture->destroy();
+}
+
+void TextureTarget::create() {
+ _texture->create();
+
+ _needUpdate = true;
+}
+
+void TextureTarget::setSize(uint width, uint height) {
+ _texture->setSize(width, height);
+
+ const uint texWidth = _texture->getWidth();
+ const uint texHeight = _texture->getHeight();
+
+ // Set viewport dimensions.
+ _viewport[0] = 0;
+ _viewport[1] = 0;
+ _viewport[2] = texWidth;
+ _viewport[3] = texHeight;
+
+ // Setup orthogonal projection matrix.
+ _projectionMatrix[ 0] = 2.0f / texWidth;
+ _projectionMatrix[ 1] = 0.0f;
+ _projectionMatrix[ 2] = 0.0f;
+ _projectionMatrix[ 3] = 0.0f;
+
+ _projectionMatrix[ 4] = 0.0f;
+ _projectionMatrix[ 5] = 2.0f / texHeight;
+ _projectionMatrix[ 6] = 0.0f;
+ _projectionMatrix[ 7] = 0.0f;
+
+ _projectionMatrix[ 8] = 0.0f;
+ _projectionMatrix[ 9] = 0.0f;
+ _projectionMatrix[10] = 0.0f;
+ _projectionMatrix[11] = 0.0f;
+
+ _projectionMatrix[12] = -1.0f;
+ _projectionMatrix[13] = -1.0f;
+ _projectionMatrix[14] = 0.0f;
+ _projectionMatrix[15] = 1.0f;
+
+ // Directly apply changes when we are active.
+ if (isActive()) {
+ applyViewport();
+ applyProjectionMatrix();
+ }
+}
+#endif // !USE_FORCED_GLES
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/framebuffer.h b/backends/graphics/opengl/framebuffer.h
new file mode 100644
index 0000000000..c44c98ddc4
--- /dev/null
+++ b/backends/graphics/opengl/framebuffer.h
@@ -0,0 +1,175 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_FRAMEBUFFER_H
+#define BACKENDS_GRAPHICS_OPENGL_FRAMEBUFFER_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+namespace OpenGL {
+
+/**
+ * Object describing a framebuffer OpenGL can render to.
+ */
+class Framebuffer {
+ friend class Pipeline;
+public:
+ Framebuffer();
+ virtual ~Framebuffer() {};
+
+public:
+ /**
+ * Set the clear color of the framebuffer.
+ */
+ void setClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+
+ /**
+ * Enable/disable GL_BLEND.
+ */
+ void enableBlend(bool enable);
+
+ /**
+ * Enable/disable GL_SCISSOR_TEST.
+ */
+ void enableScissorTest(bool enable);
+
+ /**
+ * Set scissor box dimensions.
+ */
+ void setScissorBox(GLint x, GLint y, GLsizei w, GLsizei h);
+
+ /**
+ * Obtain projection matrix of the framebuffer.
+ */
+ const GLfloat *getProjectionMatrix() const { return _projectionMatrix; }
+protected:
+ bool isActive() const { return _isActive; }
+
+ GLint _viewport[4];
+ void applyViewport();
+
+ GLfloat _projectionMatrix[4*4];
+ void applyProjectionMatrix();
+
+ /**
+ * Activate framebuffer.
+ *
+ * This is supposed to set all state associated with the framebuffer.
+ */
+ virtual void activateInternal() = 0;
+
+ /**
+ * Deactivate framebuffer.
+ *
+ * This is supposed to make any cleanup required when unbinding the
+ * framebuffer.
+ */
+ virtual void deactivateInternal() {}
+
+private:
+ /**
+ * Accessor to activate framebuffer for pipeline.
+ */
+ void activate();
+
+ /**
+ * Accessor to deactivate framebuffer from pipeline.
+ */
+ void deactivate();
+
+private:
+ bool _isActive;
+
+ GLfloat _clearColor[4];
+ void applyClearColor();
+
+ bool _blendState;
+ void applyBlendState();
+
+ bool _scissorTestState;
+ void applyScissorTestState();
+
+ GLint _scissorBox[4];
+ void applyScissorBox();
+};
+
+/**
+ * Default back buffer implementation.
+ */
+class Backbuffer : public Framebuffer {
+public:
+ /**
+ * Set the dimensions (a.k.a. size) of the back buffer.
+ */
+ void setDimensions(uint width, uint height);
+
+protected:
+ virtual void activateInternal();
+};
+
+#if !USE_FORCED_GLES
+class GLTexture;
+
+/**
+ * Render to texture framebuffer implementation.
+ *
+ * This target allows to render to a texture, which can then be used for
+ * further rendering.
+ */
+class TextureTarget : public Framebuffer {
+public:
+ TextureTarget();
+ virtual ~TextureTarget();
+
+ /**
+ * Notify that the GL context is about to be destroyed.
+ */
+ void destroy();
+
+ /**
+ * Notify that the GL context has been created.
+ */
+ void create();
+
+ /**
+ * Set size of the texture target.
+ */
+ void setSize(uint width, uint height);
+
+ /**
+ * Query pointer to underlying GL texture.
+ */
+ GLTexture *getTexture() const { return _texture; }
+
+protected:
+ virtual void activateInternal();
+
+private:
+ GLTexture *_texture;
+ GLuint _glFBO;
+ bool _needUpdate;
+};
+#endif
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/opengl-defs.h b/backends/graphics/opengl/opengl-defs.h
new file mode 100644
index 0000000000..733fc2933c
--- /dev/null
+++ b/backends/graphics/opengl/opengl-defs.h
@@ -0,0 +1,262 @@
+/* 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.
+ *
+ */
+
+/* This file is based on Mesa 3-D's gl.h and GLES/gl.h from Khronos Registry.
+ *
+ * Mesa 3-D's gl.h file is distributed under the following license:
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ *
+ * GLES/gl.h from Khronos Registry is distributed under the following license:
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_DEFS_H
+#define BACKENDS_GRAPHICS_OPENGL_OPENGL_DEFS_H
+
+#include "common/scummsys.h"
+
+/*
+ * Datatypes
+ */
+typedef uint GLenum;
+typedef uint8 GLboolean;
+typedef uint GLbitfield;
+typedef void GLvoid;
+typedef int8 GLbyte; /* 1-byte signed */
+typedef int16 GLshort; /* 2-byte signed */
+typedef int32 GLint; /* 4-byte signed */
+typedef uint8 GLubyte; /* 1-byte unsigned */
+typedef uint16 GLushort; /* 2-byte unsigned */
+typedef uint32 GLuint; /* 4-byte unsigned */
+typedef int32 GLsizei; /* 4-byte signed */
+typedef float GLfloat; /* single precision float */
+typedef float GLclampf; /* single precision float in [0,1] */
+typedef double GLdouble; /* double precision float */
+typedef double GLclampd; /* double precision float in [0,1] */
+typedef char GLchar;
+#if defined(MACOSX)
+typedef void *GLhandleARB;
+#else
+typedef uint GLhandleARB;
+#endif
+
+// This is an addition from us to alias ARB shader object extensions to
+// OpenGL (ES) 2.0 style functions. It only works when GLhandleARB and GLuint
+// are type compatible.
+typedef GLhandleARB GLprogram;
+typedef GLhandleARB GLshader;
+
+/*
+ * Constants
+ */
+
+/* Boolean constants */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Scissor box */
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+
+/* MatrixMode */
+#define GL_MATRIX_MODE 0x0BA0
+#define GL_MODELVIEW 0x1700
+#define GL_PROJECTION 0x1701
+#define GL_TEXTURE 0x1702
+
+/* EnableCap */
+#define GL_FOG 0x0B60
+#define GL_LIGHTING 0x0B50
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_ALPHA_TEST 0x0BC0
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_DEPTH_TEST 0x0B71
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_COLOR_ARRAY 0x8076
+#define GL_TEXTURE_COORD_ARRAY 0x8078
+
+/* ShadingModel */
+#define GL_FLAT 0x1D00
+#define GL_SMOOTH 0x1D01
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
+#define GL_POINT_SMOOTH_HINT 0x0C51
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_FOG_HINT 0x0C54
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* PixelFormat */
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+
+#define GL_RED 0x1903
+#define GL_R8 0x8229
+
+/* PixelStoreParameter */
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+
+/* Implementation limits */
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+
+#define GL_VERTEX_SHADER 0x8B31
+
+/* Programs */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_LINK_STATUS 0x8B82
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* Textures */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+
+/* GetPName */
+#define GL_VIEWPORT 0x0BA2
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+
+/* Framebuffer objects */
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_FRAMEBUFFER 0x8D40
+
+#endif
diff --git a/backends/graphics/opengl/opengl-func.h b/backends/graphics/opengl/opengl-func.h
new file mode 100644
index 0000000000..4e44c13d0f
--- /dev/null
+++ b/backends/graphics/opengl/opengl-func.h
@@ -0,0 +1,153 @@
+/* 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.
+ *
+ */
+
+/* This file is based on Mesa 3-D's gl.h and GLES/gl.h from Khronos Registry.
+ *
+ * Mesa 3-D's gl.h file is distributed under the following license:
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ *
+ * GLES/gl.h from Khronos Registry is distributed under the following license:
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*
+ * This file is a template file to be used inside specific locations in the
+ * OpenGL graphics code. It is not to be included otherwise. It intentionally
+ * does not contain include guards because it can be required to include it
+ * multiple times in a source file.
+ *
+ * Functions are defined by three different user supplied macros:
+ * GL_FUNC_DEF: Define a (builtin) OpenGL (ES) function.
+ * GL_FUNC_2_DEF: Define a OpenGL (ES) 2.0 function which can be provided by
+ * extensions in OpenGL 1.x contexts.
+ * GL_EXT_FUNC_DEF: Define an OpenGL (ES) extension function.
+ */
+
+#if !defined(GL_FUNC_2_DEF)
+#define GL_FUNC_2_DEF(ret, name, extName, param) GL_FUNC_DEF(ret, name, param)
+#define DEFINED_GL_FUNC_2_DEF
+#endif
+
+#if !defined(GL_EXT_FUNC_DEF)
+#define GL_EXT_FUNC_DEF(ret, name, param) GL_FUNC_DEF(ret, name, param)
+#define DEFINED_GL_EXT_FUNC_DEF
+#endif
+
+GL_FUNC_DEF(void, glEnable, (GLenum cap));
+GL_FUNC_DEF(void, glDisable, (GLenum cap));
+GL_FUNC_DEF(GLboolean, glIsEnabled, (GLenum cap));
+GL_FUNC_DEF(void, glClear, (GLbitfield mask));
+GL_FUNC_DEF(void, glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha));
+GL_FUNC_DEF(void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height));
+GL_FUNC_DEF(void, glMatrixMode, (GLenum mode));
+GL_FUNC_DEF(void, glLoadIdentity, ());
+GL_FUNC_DEF(void, glLoadMatrixf, (const GLfloat *m));
+GL_FUNC_DEF(void, glShadeModel, (GLenum mode));
+GL_FUNC_DEF(void, glHint, (GLenum target, GLenum mode));
+GL_FUNC_DEF(void, glClearColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha));
+GL_FUNC_DEF(void, glBlendFunc, (GLenum sfactor, GLenum dfactor));
+GL_FUNC_DEF(void, glEnableClientState, (GLenum array));
+GL_FUNC_DEF(void, glPixelStorei, (GLenum pname, GLint param));
+GL_FUNC_DEF(void, glScissor, (GLint x, GLint y, GLsizei width, GLsizei height));
+GL_FUNC_DEF(void, glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels));
+GL_FUNC_DEF(void, glGetIntegerv, (GLenum pname, GLint *params));
+GL_FUNC_DEF(void, glDeleteTextures, (GLsizei n, const GLuint *textures));
+GL_FUNC_DEF(void, glGenTextures, (GLsizei n, GLuint *textures));
+GL_FUNC_DEF(void, glBindTexture, (GLenum target, GLuint texture));
+GL_FUNC_DEF(void, glTexParameteri, (GLenum target, GLenum pname, GLint param));
+GL_FUNC_DEF(void, glTexImage2D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels));
+GL_FUNC_DEF(void, glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer));
+GL_FUNC_DEF(void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer));
+GL_FUNC_DEF(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count));
+GL_FUNC_DEF(void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels));
+GL_FUNC_DEF(const GLubyte *, glGetString, (GLenum name));
+GL_FUNC_DEF(GLenum, glGetError, ());
+
+#if !USE_FORCED_GLES
+GL_FUNC_2_DEF(void, glEnableVertexAttribArray, glEnableVertexAttribArrayARB, (GLuint index));
+GL_FUNC_2_DEF(void, glDisableVertexAttribArray, glDisableVertexAttribArrayARB, (GLuint index));
+GL_FUNC_2_DEF(void, glUniform1i, glUniform1iARB, (GLint location, GLint v0));
+GL_FUNC_2_DEF(void, glUniform1f, glUniform1fARB, (GLint location, GLfloat v0));
+GL_FUNC_2_DEF(void, glUniformMatrix4fv, glUniformMatrix4fvARB, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value));
+GL_FUNC_2_DEF(void, glVertexAttrib4f, glVertexAttrib4fARB, (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w));
+GL_FUNC_2_DEF(void, glVertexAttribPointer, glVertexAttribPointerARB, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer));
+
+GL_FUNC_2_DEF(GLprogram, glCreateProgram, glCreateProgramObjectARB, ());
+GL_FUNC_2_DEF(void, glDeleteProgram, glDeleteObjectARB, (GLprogram program));
+GL_FUNC_2_DEF(void, glAttachShader, glAttachObjectARB, (GLprogram program, GLshader shader));
+GL_FUNC_2_DEF(void, glDetachShader, glDetachObjectARB, (GLprogram program, GLshader shader));
+GL_FUNC_2_DEF(void, glLinkProgram, glLinkProgramARB, (GLprogram program));
+GL_FUNC_2_DEF(void, glUseProgram, glUseProgramObjectARB, (GLprogram program));
+GL_FUNC_2_DEF(void, glGetProgramiv, glGetObjectParameterivARB, (GLprogram program, GLenum pname, GLint *params));
+GL_FUNC_2_DEF(void, glGetProgramInfoLog, glGetInfoLogARB, (GLprogram program, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
+GL_FUNC_2_DEF(void, glBindAttribLocation, glBindAttribLocationARB, (GLprogram program, GLuint index, const GLchar *name));
+GL_FUNC_2_DEF(GLint, glGetAttribLocation, glGetAttribLocationARB, (GLprogram program, const GLchar *name));
+GL_FUNC_2_DEF(GLint, glGetUniformLocation, glGetUniformLocationARB, (GLprogram program, const GLchar *name));
+
+GL_FUNC_2_DEF(GLshader, glCreateShader, glCreateShaderObjectARB, (GLenum type));
+GL_FUNC_2_DEF(void, glDeleteShader, glDeleteObjectARB, (GLshader shader));
+GL_FUNC_2_DEF(void, glGetShaderiv, glGetObjectParameterivARB, (GLshader shader, GLenum pname, GLint *params));
+GL_FUNC_2_DEF(void, glGetShaderInfoLog, glGetInfoLogARB, (GLshader shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog));
+GL_FUNC_2_DEF(void, glShaderSource, glShaderSourceARB, (GLshader shader, GLsizei count, const GLchar *const *string, const GLint *length));
+GL_FUNC_2_DEF(void, glCompileShader, glCompileShaderARB, (GLshader shader));
+
+GL_FUNC_2_DEF(void, glBindFramebuffer, glBindFramebufferEXT, (GLenum target, GLuint renderbuffer));
+GL_FUNC_2_DEF(void, glDeleteFramebuffers, glDeleteFramebuffersEXT, (GLsizei n, const GLuint *framebuffers));
+GL_FUNC_2_DEF(void, glGenFramebuffers, glGenFramebuffersEXT, (GLsizei n, GLuint *renderbuffers));
+GL_FUNC_2_DEF(void, glFramebufferTexture2D, glFramebufferTexture2DEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level));
+GL_FUNC_2_DEF(GLenum, glCheckFramebufferStatus, glCheckFramebufferStatusEXT, (GLenum target));
+
+GL_FUNC_2_DEF(void, glActiveTexture, glActiveTextureARB, (GLenum texture));
+#endif
+
+#ifdef DEFINED_GL_EXT_FUNC_DEF
+#undef DEFINED_GL_EXT_FUNC_DEF
+#undef GL_EXT_FUNC_DEF
+#endif
+
+#ifdef DEFINED_GL_FUNC_2_DEF
+#undef DEFINED_GL_FUNC_2_DEF
+#undef GL_FUNC_2_DEF
+#endif
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index ac6d41d47d..4d6a00a3b3 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -23,8 +23,10 @@
#include "backends/graphics/opengl/opengl-graphics.h"
#include "backends/graphics/opengl/texture.h"
-#include "backends/graphics/opengl/debug.h"
-#include "backends/graphics/opengl/extensions.h"
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+#include "backends/graphics/opengl/pipelines/fixed.h"
+#include "backends/graphics/opengl/pipelines/shader.h"
+#include "backends/graphics/opengl/shader.h"
#include "common/textconsole.h"
#include "common/translation.h"
@@ -45,6 +47,7 @@ namespace OpenGL {
OpenGLGraphicsManager::OpenGLGraphicsManager()
: _currentState(), _oldState(), _transactionMode(kTransactionNone), _screenChangeID(1 << (sizeof(int) * 8 - 2)),
+ _pipeline(nullptr),
_outputScreenWidth(0), _outputScreenHeight(0), _displayX(0), _displayY(0),
_displayWidth(0), _displayHeight(0), _defaultFormat(), _defaultFormatAlpha(),
_gameScreen(nullptr), _gameScreenShakeOffset(0), _overlay(nullptr),
@@ -58,6 +61,7 @@ OpenGLGraphicsManager::OpenGLGraphicsManager()
#endif
{
memset(_gamePalette, 0, sizeof(_gamePalette));
+ g_context.reset();
}
OpenGLGraphicsManager::~OpenGLGraphicsManager() {
@@ -67,6 +71,9 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
#ifdef USE_OSD
delete _osd;
#endif
+#if !USE_FORCED_GLES
+ ShaderManager::destroy();
+#endif
}
bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) {
@@ -215,8 +222,8 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
// a context existing before, which means we don't know the maximum
// supported texture size before this. Thus, we check whether the
// requested game resolution is supported over here.
- || ( _currentState.gameWidth > (uint)Texture::getMaximumTextureSize()
- || _currentState.gameHeight > (uint)Texture::getMaximumTextureSize())) {
+ || ( _currentState.gameWidth > (uint)g_context.maxTextureSize
+ || _currentState.gameHeight > (uint)g_context.maxTextureSize)) {
if (_transactionMode == kTransactionActive) {
// Try to setup the old state in case its valid and is
// actually different from the new one.
@@ -267,9 +274,9 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() {
_gameScreen = nullptr;
#ifdef USE_RGB_COLOR
- _gameScreen = createTexture(_currentState.gameFormat);
+ _gameScreen = createSurface(_currentState.gameFormat);
#else
- _gameScreen = createTexture(Graphics::PixelFormat::createFormatCLUT8());
+ _gameScreen = createSurface(Graphics::PixelFormat::createFormatCLUT8());
#endif
assert(_gameScreen);
if (_gameScreen->hasPalette()) {
@@ -365,29 +372,37 @@ void OpenGLGraphicsManager::updateScreen() {
}
_forceRedraw = false;
+ // Update changes to textures.
+ _gameScreen->updateGLTexture();
+ if (_cursor) {
+ _cursor->updateGLTexture();
+ }
+ _overlay->updateGLTexture();
+ _osd->updateGLTexture();
+
// Clear the screen buffer.
if (_scissorOverride && !_overlayVisible) {
// In certain cases we need to assure that the whole screen area is
// cleared. For example, when switching from overlay visible to
// invisible, we need to assure that all contents are cleared to
// properly remove all overlay contents.
- GLCALL(glDisable(GL_SCISSOR_TEST));
- GLCALL(glClear(GL_COLOR_BUFFER_BIT));
- GLCALL(glEnable(GL_SCISSOR_TEST));
+ _backBuffer.enableScissorTest(false);
+ GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
+ _backBuffer.enableScissorTest(true);
--_scissorOverride;
} else {
- GLCALL(glClear(GL_COLOR_BUFFER_BIT));
+ GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
}
const GLfloat shakeOffset = _gameScreenShakeOffset * (GLfloat)_displayHeight / _gameScreen->getHeight();
// First step: Draw the (virtual) game screen.
- _gameScreen->draw(_displayX, _displayY + shakeOffset, _displayWidth, _displayHeight);
+ g_context.getActivePipeline()->drawTexture(_gameScreen->getGLTexture(), _displayX, _displayY + shakeOffset, _displayWidth, _displayHeight);
// Second step: Draw the overlay if visible.
if (_overlayVisible) {
- _overlay->draw(0, 0, _outputScreenWidth, _outputScreenHeight);
+ g_context.getActivePipeline()->drawTexture(_overlay->getGLTexture(), 0, 0, _outputScreenWidth, _outputScreenHeight);
}
// Third step: Draw the cursor if visible.
@@ -396,9 +411,10 @@ void OpenGLGraphicsManager::updateScreen() {
// visible.
const GLfloat cursorOffset = _overlayVisible ? 0 : shakeOffset;
- _cursor->draw(_cursorDisplayX - _cursorHotspotXScaled,
- _cursorDisplayY - _cursorHotspotYScaled + cursorOffset,
- _cursorWidthScaled, _cursorHeightScaled);
+ g_context.getActivePipeline()->drawTexture(_cursor->getGLTexture(),
+ _cursorDisplayX - _cursorHotspotXScaled,
+ _cursorDisplayY - _cursorHotspotYScaled + cursorOffset,
+ _cursorWidthScaled, _cursorHeightScaled);
}
#ifdef USE_OSD
@@ -419,13 +435,13 @@ void OpenGLGraphicsManager::updateScreen() {
}
// Set the OSD transparency.
- GLCALL(glColor4f(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f));
+ g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, _osdAlpha / 100.0f);
// Draw the OSD texture.
- _osd->draw(0, 0, _outputScreenWidth, _outputScreenHeight);
+ g_context.getActivePipeline()->drawTexture(_osd->getGLTexture(), 0, 0, _outputScreenWidth, _outputScreenHeight);
// Reset color.
- GLCALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
+ g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
}
#endif
@@ -467,7 +483,7 @@ void OpenGLGraphicsManager::showOverlay() {
_forceRedraw = true;
// Allow drawing inside full screen area.
- GLCALL(glDisable(GL_SCISSOR_TEST));
+ _backBuffer.enableScissorTest(false);
// Update cursor position.
setMousePosition(_cursorX, _cursorY);
@@ -478,7 +494,7 @@ void OpenGLGraphicsManager::hideOverlay() {
_forceRedraw = true;
// Limit drawing to screen area.
- GLCALL(glEnable(GL_SCISSOR_TEST));
+ _backBuffer.enableScissorTest(true);
_scissorOverride = 3;
// Update cursor position.
@@ -609,7 +625,7 @@ void OpenGLGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int
} else {
textureFormat = _defaultFormatAlpha;
}
- _cursor = createTexture(textureFormat, true);
+ _cursor = createSurface(textureFormat, true);
assert(_cursor);
_cursor->enableLinearFiltering(_currentState.graphicsMode == GFX_LINEAR);
}
@@ -755,18 +771,8 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
_outputScreenWidth = width;
_outputScreenHeight = height;
- // Setup coordinates system.
- GLCALL(glViewport(0, 0, _outputScreenWidth, _outputScreenHeight));
-
- GLCALL(glMatrixMode(GL_PROJECTION));
- GLCALL(glLoadIdentity());
-#ifdef USE_GLES
- GLCALL(glOrthof(0, _outputScreenWidth, _outputScreenHeight, 0, -1, 1));
-#else
- GLCALL(glOrtho(0, _outputScreenWidth, _outputScreenHeight, 0, -1, 1));
-#endif
- GLCALL(glMatrixMode(GL_MODELVIEW));
- GLCALL(glLoadIdentity());
+ // Setup backbuffer size.
+ _backBuffer.setDimensions(width, height);
uint overlayWidth = width;
uint overlayHeight = height;
@@ -777,15 +783,15 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
// possible and then scale it to the physical display size. This sounds
// bad but actually all recent chips should support full HD resolution
// anyway. Thus, it should not be a real issue for modern hardware.
- if ( overlayWidth > (uint)Texture::getMaximumTextureSize()
- || overlayHeight > (uint)Texture::getMaximumTextureSize()) {
+ if ( overlayWidth > (uint)g_context.maxTextureSize
+ || overlayHeight > (uint)g_context.maxTextureSize) {
const frac_t outputAspect = intToFrac(_outputScreenWidth) / _outputScreenHeight;
if (outputAspect > (frac_t)FRAC_ONE) {
- overlayWidth = Texture::getMaximumTextureSize();
+ overlayWidth = g_context.maxTextureSize;
overlayHeight = intToFrac(overlayWidth) / outputAspect;
} else {
- overlayHeight = Texture::getMaximumTextureSize();
+ overlayHeight = g_context.maxTextureSize;
overlayWidth = fracToInt(overlayHeight * outputAspect);
}
}
@@ -801,7 +807,7 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
delete _overlay;
_overlay = nullptr;
- _overlay = createTexture(_defaultFormatAlpha);
+ _overlay = createSurface(_defaultFormatAlpha);
assert(_overlay);
// We always filter the overlay with GL_LINEAR. This assures it's
// readable in case it needs to be scaled and does not affect it
@@ -816,7 +822,7 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
delete _osd;
_osd = nullptr;
- _osd = createTexture(_defaultFormatAlpha);
+ _osd = createSurface(_defaultFormatAlpha);
assert(_osd);
// We always filter the osd with GL_LINEAR. This assures it's
// readable in case it needs to be scaled and does not affect it
@@ -836,38 +842,48 @@ void OpenGLGraphicsManager::setActualScreenSize(uint width, uint height) {
}
void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &defaultFormat, const Graphics::PixelFormat &defaultFormatAlpha) {
- // Initialize all extensions.
- initializeGLExtensions();
+ // Initialize context for use.
+ initializeGLContext();
- // Disable 3D properties.
- GLCALL(glDisable(GL_CULL_FACE));
- GLCALL(glDisable(GL_DEPTH_TEST));
- GLCALL(glDisable(GL_LIGHTING));
- GLCALL(glDisable(GL_FOG));
- GLCALL(glDisable(GL_DITHER));
- GLCALL(glShadeModel(GL_FLAT));
- GLCALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
+ // Initialize pipeline.
+ delete _pipeline;
+ _pipeline = nullptr;
- // Default to black as clear color.
- GLCALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
- GLCALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
+#if !USE_FORCED_GLES
+ if (g_context.shadersSupported) {
+ ShaderMan.notifyCreate();
+ _pipeline = new ShaderPipeline(ShaderMan.query(ShaderManager::kDefault));
+ }
+#endif
- // Setup alpha blend (for overlay and cursor).
- GLCALL(glEnable(GL_BLEND));
- GLCALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+#if !USE_FORCED_GLES2
+ if (_pipeline == nullptr) {
+ _pipeline = new FixedPipeline();
+ }
+#endif
+
+ g_context.setPipeline(_pipeline);
+
+ // Disable 3D properties.
+ GL_CALL(glDisable(GL_CULL_FACE));
+ GL_CALL(glDisable(GL_DEPTH_TEST));
+ GL_CALL(glDisable(GL_DITHER));
- // Enable rendering with vertex and coord arrays.
- GLCALL(glEnableClientState(GL_VERTEX_ARRAY));
- GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+ g_context.getActivePipeline()->setColor(1.0f, 1.0f, 1.0f, 1.0f);
- GLCALL(glEnable(GL_TEXTURE_2D));
+ GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
+ // Setup backbuffer state.
+
+ // Default to black as clear color.
+ _backBuffer.setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ // Setup alpha blend (for overlay and cursor).
+ _backBuffer.enableBlend(true);
// Setup scissor state accordingly.
- if (_overlayVisible) {
- GLCALL(glDisable(GL_SCISSOR_TEST));
- } else {
- GLCALL(glEnable(GL_SCISSOR_TEST));
- }
+ _backBuffer.enableScissorTest(!_overlayVisible);
+
+ g_context.getActivePipeline()->setFramebuffer(&_backBuffer);
+
// Clear the whole screen for the first three frames to assure any
// leftovers are cleared.
_scissorOverride = 3;
@@ -875,10 +891,7 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def
// We use a "pack" alignment (when reading from textures) to 4 here,
// since the only place where we really use it is the BMP screenshot
// code and that requires the same alignment too.
- GLCALL(glPixelStorei(GL_PACK_ALIGNMENT, 4));
-
- // Query information needed by textures.
- Texture::queryTextureInformation();
+ GL_CALL(glPixelStorei(GL_PACK_ALIGNMENT, 4));
// Refresh the output screen dimensions if some are set up.
if (_outputScreenWidth != 0 && _outputScreenHeight != 0) {
@@ -892,42 +905,56 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def
_defaultFormatAlpha = defaultFormatAlpha;
if (_gameScreen) {
- _gameScreen->recreateInternalTexture();
+ _gameScreen->recreate();
}
if (_overlay) {
- _overlay->recreateInternalTexture();
+ _overlay->recreate();
}
if (_cursor) {
- _cursor->recreateInternalTexture();
+ _cursor->recreate();
}
#ifdef USE_OSD
if (_osd) {
- _osd->recreateInternalTexture();
+ _osd->recreate();
}
#endif
}
void OpenGLGraphicsManager::notifyContextDestroy() {
if (_gameScreen) {
- _gameScreen->releaseInternalTexture();
+ _gameScreen->destroy();
}
if (_overlay) {
- _overlay->releaseInternalTexture();
+ _overlay->destroy();
}
if (_cursor) {
- _cursor->releaseInternalTexture();
+ _cursor->destroy();
}
#ifdef USE_OSD
if (_osd) {
- _osd->releaseInternalTexture();
+ _osd->destroy();
}
#endif
+
+#if !USE_FORCED_GLES
+ if (g_context.shadersSupported) {
+ ShaderMan.notifyDestroy();
+ }
+#endif
+
+ // Destroy rendering pipeline.
+ g_context.setPipeline(nullptr);
+ delete _pipeline;
+ _pipeline = nullptr;
+
+ // Rest our context description since the context is gone soon.
+ g_context.reset();
}
void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) {
@@ -970,9 +997,15 @@ void OpenGLGraphicsManager::setMousePosition(int x, int y) {
}
}
-Texture *OpenGLGraphicsManager::createTexture(const Graphics::PixelFormat &format, bool wantAlpha) {
+Surface *OpenGLGraphicsManager::createSurface(const Graphics::PixelFormat &format, bool wantAlpha) {
GLenum glIntFormat, glFormat, glType;
if (format.bytesPerPixel == 1) {
+#if !USE_FORCED_GLES
+ if (TextureCLUT8GPU::isSupportedByContext()) {
+ return new TextureCLUT8GPU();
+ }
+#endif
+
const Graphics::PixelFormat &virtFormat = wantAlpha ? _defaultFormatAlpha : _defaultFormat;
const bool supported = getGLPixelFormat(virtFormat, glIntFormat, glFormat, glType);
if (!supported) {
@@ -980,6 +1013,15 @@ Texture *OpenGLGraphicsManager::createTexture(const Graphics::PixelFormat &forma
} else {
return new TextureCLUT8(glIntFormat, glFormat, glType, virtFormat);
}
+#if !USE_FORCED_GL
+ } else if (isGLESContext() && format == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) {
+ // OpenGL ES does not support a texture format usable for RGB555.
+ // Since SCUMM uses this pixel format for some games (and there is no
+ // hope for this to change anytime soon) we use pixel format
+ // conversion to a supported texture format. However, this is a one
+ // time exception.
+ return new TextureRGB555();
+#endif // !USE_FORCED_GL
} else {
const bool supported = getGLPixelFormat(format, glIntFormat, glFormat, glType);
if (!supported) {
@@ -1015,7 +1057,11 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF
glFormat = GL_RGBA;
glType = GL_UNSIGNED_SHORT_4_4_4_4;
return true;
-#ifndef USE_GLES
+#if !USE_FORCED_GLES && !USE_FORCED_GLES2
+ // The formats below are not supported by every GLES implementation.
+ // Thus, we do not mark them as supported when a GLES context is setup.
+ } else if (isGLESContext()) {
+ return false;
#ifdef SCUMM_LITTLE_ENDIAN
} else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { // RGBA8888
glIntFormat = GL_RGBA;
@@ -1024,17 +1070,10 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF
return true;
#endif
} else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)) { // RGB555
- // GL_BGRA does not exist in every GLES implementation so should not be configured if
- // USE_GLES is set.
glIntFormat = GL_RGB;
glFormat = GL_BGRA;
glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
return true;
- } else if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)) { // ARGB8888
- glIntFormat = GL_RGBA;
- glFormat = GL_BGRA;
- glType = GL_UNSIGNED_INT_8_8_8_8_REV;
- return true;
} else if (pixelFormat == Graphics::PixelFormat(2, 4, 4, 4, 4, 8, 4, 0, 12)) { // ARGB4444
glIntFormat = GL_RGBA;
glFormat = GL_BGRA;
@@ -1054,8 +1093,8 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF
return true;
} else if (pixelFormat == Graphics::PixelFormat(2, 5, 6, 5, 0, 0, 5, 11, 0)) { // BGR565
glIntFormat = GL_RGB;
- glFormat = GL_BGR;
- glType = GL_UNSIGNED_SHORT_5_6_5;
+ glFormat = GL_RGB;
+ glType = GL_UNSIGNED_SHORT_5_6_5_REV;
return true;
} else if (pixelFormat == Graphics::PixelFormat(2, 5, 5, 5, 1, 1, 6, 11, 0)) { // BGRA5551
glIntFormat = GL_RGBA;
@@ -1072,7 +1111,7 @@ bool OpenGLGraphicsManager::getGLPixelFormat(const Graphics::PixelFormat &pixelF
glFormat = GL_BGRA;
glType = GL_UNSIGNED_SHORT_4_4_4_4;
return true;
-#endif
+#endif // !USE_FORCED_GLES && !USE_FORCED_GLES2
} else {
return false;
}
@@ -1119,10 +1158,10 @@ void OpenGLGraphicsManager::recalculateDisplayArea() {
// Setup drawing limitation for game graphics.
// This invovles some trickery because OpenGL's viewport coordinate system
// is upside down compared to ours.
- GLCALL(glScissor(_displayX,
- _outputScreenHeight - _displayHeight - _displayY,
- _displayWidth,
- _displayHeight));
+ _backBuffer.setScissorBox(_displayX,
+ _outputScreenHeight - _displayHeight - _displayY,
+ _displayWidth,
+ _displayHeight);
// Clear the whole screen for the first three frames to remove leftovers.
_scissorOverride = 3;
@@ -1144,20 +1183,7 @@ void OpenGLGraphicsManager::updateCursorPalette() {
_cursor->setPalette(0, 256, _gamePalette);
}
- // We remove all alpha bits from the palette entry of the color key.
- // This makes sure its properly handled as color key.
- const Graphics::PixelFormat &hardwareFormat = _cursor->getHardwareFormat();
- const uint32 aMask = (0xFF >> hardwareFormat.aLoss) << hardwareFormat.aShift;
-
- if (hardwareFormat.bytesPerPixel == 2) {
- uint16 *palette = (uint16 *)_cursor->getPalette() + _cursorKeyColor;
- *palette &= ~aMask;
- } else if (hardwareFormat.bytesPerPixel == 4) {
- uint32 *palette = (uint32 *)_cursor->getPalette() + _cursorKeyColor;
- *palette &= ~aMask;
- } else {
- warning("OpenGLGraphicsManager::updateCursorPalette: Unsupported pixel depth %d", hardwareFormat.bytesPerPixel);
- }
+ _cursor->setColorKey(_cursorKeyColor);
}
void OpenGLGraphicsManager::recalculateCursorScaling() {
@@ -1207,7 +1233,7 @@ void OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const
uint8 *pixels = new uint8[lineSize * height];
// Get pixel data from OpenGL buffer
- GLCALL(glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels));
+ GL_CALL(glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels));
// BMP stores as BGR. Since we can't assume that GL_BGR is supported we
// will swap the components from the RGB we read to BGR on our own.
diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h
index 9578839383..35435c156e 100644
--- a/backends/graphics/opengl/opengl-graphics.h
+++ b/backends/graphics/opengl/opengl-graphics.h
@@ -24,6 +24,7 @@
#define BACKENDS_GRAPHICS_OPENGL_OPENGL_GRAPHICS_H
#include "backends/graphics/opengl/opengl-sys.h"
+#include "backends/graphics/opengl/framebuffer.h"
#include "backends/graphics/graphics.h"
#include "common/frac.h"
@@ -40,7 +41,11 @@ namespace OpenGL {
// SurfaceSDL backend enables it and disabling it can cause issues in sdl.cpp.
#define USE_OSD 1
-class Texture;
+class Surface;
+class Pipeline;
+#if !USE_FORCED_GLES
+class Shader;
+#endif
enum {
GFX_LINEAR = 0,
@@ -117,6 +122,11 @@ public:
protected:
/**
+ * Whether an GLES or GLES2 context is active.
+ */
+ bool isGLESContext() const { return g_context.type == kContextGLES || g_context.type == kContextGLES2; }
+
+ /**
* Set up the actual screen size available for the OpenGL code to do any
* drawing.
*
@@ -126,6 +136,16 @@ protected:
void setActualScreenSize(uint width, uint height);
/**
+ * Sets the OpenGL (ES) type the graphics manager shall work with.
+ *
+ * This needs to be called at least once (and before ever calling
+ * notifyContextCreate).
+ *
+ * @param type Type of the OpenGL (ES) contexts to be created.
+ */
+ void setContextType(ContextType type);
+
+ /**
* Notify the manager of a OpenGL context change. This should be the first
* thing to call after you created an OpenGL (ES) context!
*
@@ -172,15 +192,15 @@ protected:
private:
/**
- * Create a texture with the specified pixel format.
+ * Create a surface with the specified pixel format.
*
- * @param format The pixel format the Texture object should accept as
+ * @param format The pixel format the Surface object should accept as
* input.
- * @param wantAlpha For CLUT8 textures this marks whether an alpha
+ * @param wantAlpha For CLUT8 surfaces this marks whether an alpha
* channel should be used.
- * @return A pointer to the texture or nullptr on failure.
+ * @return A pointer to the surface or nullptr on failure.
*/
- Texture *createTexture(const Graphics::PixelFormat &format, bool wantAlpha = false);
+ Surface *createSurface(const Graphics::PixelFormat &format, bool wantAlpha = false);
//
// Transaction support
@@ -281,6 +301,36 @@ private:
//
/**
+ * Initialize the active context for use.
+ */
+ void initializeGLContext();
+
+ /**
+ * Render back buffer.
+ */
+ Backbuffer _backBuffer;
+
+ /**
+ * OpenGL pipeline used for rendering.
+ */
+ Pipeline *_pipeline;
+
+protected:
+ /**
+ * Query the address of an OpenGL function by name.
+ *
+ * This can only be used after a context has been created.
+ * Please note that this function can return valid addresses even if the
+ * OpenGL context does not support the function.
+ *
+ * @param name The name of the OpenGL function.
+ * @return An function pointer for the requested OpenGL function or
+ * nullptr in case of failure.
+ */
+ virtual void *getProcAddress(const char *name) const = 0;
+
+private:
+ /**
* Try to determine the internal parameters for a given pixel format.
*
* @return true when the format can be used, false otherwise.
@@ -348,7 +398,7 @@ private:
/**
* The virtual game screen.
*/
- Texture *_gameScreen;
+ Surface *_gameScreen;
/**
* The game palette if in CLUT8 mode.
@@ -367,7 +417,7 @@ private:
/**
* The overlay screen.
*/
- Texture *_overlay;
+ Surface *_overlay;
/**
* Whether the overlay is visible or not.
@@ -386,7 +436,7 @@ private:
/**
* The cursor image.
*/
- Texture *_cursor;
+ Surface *_cursor;
/**
* X coordinate of the cursor in phyiscal coordinates.
@@ -497,7 +547,7 @@ private:
/**
* The OSD's contents.
*/
- Texture *_osd;
+ Surface *_osd;
/**
* Current opacity level of the OSD.
diff --git a/backends/graphics/opengl/opengl-sys.h b/backends/graphics/opengl/opengl-sys.h
index 4e21894380..4495128f32 100644
--- a/backends/graphics/opengl/opengl-sys.h
+++ b/backends/graphics/opengl/opengl-sys.h
@@ -23,35 +23,147 @@
#ifndef BACKENDS_GRAPHICS_OPENGL_OPENGL_SYS_H
#define BACKENDS_GRAPHICS_OPENGL_OPENGL_SYS_H
-// The purpose of this header is to include the OpenGL headers in an uniform
-// fashion. A notable example for a non standard port is the Tizen port.
-
#include "common/scummsys.h"
-#ifdef WIN32
-#if defined(ARRAYSIZE) && !defined(_WINDOWS_)
-#undef ARRAYSIZE
-#endif
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef ARRAYSIZE
+#include "backends/graphics/opengl/debug.h"
+#ifdef SDL_BACKEND
+#include "backends/platform/sdl/sdl-sys.h"
#endif
-// HACK: In case common/util.h has been included already we need to make sure
-// to define ARRAYSIZE again in case of Windows.
-#if !defined(ARRAYSIZE) && defined(COMMON_UTIL_H)
-#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
+// On OS X we only support GL contexts. The reason is that Apple's GL interface
+// uses "void *" for GLhandleARB which is not type compatible with GLint. This
+// kills our aliasing trick for extension functions and thus would force us to
+// supply two different Shader class implementations or introduce other
+// wrappers. OS X only supports GL contexts right now anyway (at least
+// according to SDL2 sources), thus it is not much of an issue.
+#if defined(MACOSX) && (!defined(USE_GLES_MODE) || USE_GLES_MODE != 0)
+//#warning "Only forced OpenGL mode is supported on Mac OS X. Overriding settings."
+#undef USE_GLES_MODE
+#define USE_GLES_MODE 0
#endif
+// We allow to force GL or GLES modes on compile time.
+// For this the USE_GLES_MODE define is used. The following values represent
+// the given selection choices:
+// 0 - Force OpenGL context
+// 1 - Force OpenGL ES context
+// 2 - Force OpenGL ES 2.0 context
+#define USE_FORCED_GL (defined(USE_GLES_MODE) && USE_GLES_MODE == 0)
+#define USE_FORCED_GLES (defined(USE_GLES_MODE) && USE_GLES_MODE == 1)
+#define USE_FORCED_GLES2 (defined(USE_GLES_MODE) && USE_GLES_MODE == 2)
+
+// On Tizen we include the toolchain's OpenGL file. This is something we
+// actually want to avoid. However, since Tizen uses eglGetProcAddress which
+// is not required to return valid function pointers to non OpenGL extension
+// functions, we need the system's definitions to resolve all OpenGL
+// functions.
+// TODO: See if there is an alternative which allows us to avoid including
+// Tizen's OpenGL header here.
#if defined(TIZEN)
-#include <FGraphicsOpengl.h>
-using namespace Tizen::Graphics::Opengl;
-#elif defined(USE_GLES)
-#include <GLES/gl.h>
-#elif defined(SDL_BACKEND)
-#include <SDL_opengl.h>
+ #include <FGraphicsOpengl.h>
+ using namespace Tizen::Graphics::Opengl;
+ #define USE_BUILTIN_OPENGL
#else
-#include <GL/gl.h>
+ #include "backends/graphics/opengl/opengl-defs.h"
#endif
+#ifdef SDL_BACKEND
+ // Win32 needs OpenGL functions declared with APIENTRY.
+ // However, SDL does not define APIENTRY in it's SDL.h file on non-Windows
+ // targets, thus if it is not available, we just dummy define it.
+ #ifndef APIENTRY
+ #define APIENTRY
+ #endif
+ #define GL_CALL_CONV APIENTRY
+#else
+ #define GL_CALL_CONV
+#endif
+
+namespace OpenGL {
+
+enum ContextType {
+ kContextGL,
+ kContextGLES,
+ kContextGLES2
+};
+
+class Pipeline;
+class Framebuffer;
+
+/**
+ * Description structure of the OpenGL (ES) context.
+ */
+struct Context {
+ /** The type of the active context. */
+ ContextType type;
+
+ /**
+ * Reset context.
+ *
+ * This marks all extensions as unavailable and clears all function
+ * pointers.
+ */
+ void reset();
+
+ /** The maximum texture size supported by the context. */
+ GLint maxTextureSize;
+
+ /** Whether GL_ARB_texture_non_power_of_two is available or not. */
+ bool NPOTSupported;
+
+ /** Whether shader support is available or not. */
+ bool shadersSupported;
+
+ /** Whether multi texture support is available or not. */
+ bool multitextureSupported;
+
+ /** Whether FBO support is available or not. */
+ bool framebufferObjectSupported;
+
+#define GL_FUNC_DEF(ret, name, param) ret (GL_CALL_CONV *name)param
+#include "backends/graphics/opengl/opengl-func.h"
+#undef GL_FUNC_DEF
+
+ //
+ // Wrapper functionality to handle fixed-function pipelines and
+ // programmable pipelines in the same fashion.
+ //
+
+private:
+ /** Currently active rendering pipeline. */
+ Pipeline *activePipeline;
+
+public:
+ /**
+ * Set new pipeline.
+ *
+ * Client is responsible for any memory management related to pipelines.
+ *
+ * @param pipeline Pipeline to activate.
+ * @return Formerly active pipeline.
+ */
+ Pipeline *setPipeline(Pipeline *pipeline);
+
+ /**
+ * Query the currently active rendering pipeline.
+ */
+ Pipeline *getActivePipeline() const { return activePipeline; }
+};
+
+/**
+ * The (active) OpenGL context.
+ */
+extern Context g_context;
+
+} // End of namespace OpenGL
+
+#define GL_CALL(x) GL_WRAP_DEBUG(g_context.x, x)
+#define GL_CALL_SAFE(func, params) \
+ do { \
+ if (g_context.func) { \
+ GL_CALL(func params); \
+ } \
+ } while (0)
+#define GL_ASSIGN(var, x) GL_WRAP_DEBUG(var = g_context.x, x)
+
#endif
diff --git a/backends/graphics/opengl/pipelines/clut8.cpp b/backends/graphics/opengl/pipelines/clut8.cpp
new file mode 100644
index 0000000000..fca40074f0
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/clut8.cpp
@@ -0,0 +1,46 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/pipelines/clut8.h"
+#include "backends/graphics/opengl/shader.h"
+#include "backends/graphics/opengl/framebuffer.h"
+
+namespace OpenGL {
+
+#if !USE_FORCED_GLES
+CLUT8LookUpPipeline::CLUT8LookUpPipeline()
+ : ShaderPipeline(ShaderMan.query(ShaderManager::kCLUT8LookUp)), _paletteTexture(nullptr) {
+}
+
+void CLUT8LookUpPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates) {
+ // Set the palette texture.
+ GL_CALL(glActiveTexture(GL_TEXTURE1));
+ if (_paletteTexture) {
+ _paletteTexture->bind();
+ }
+
+ GL_CALL(glActiveTexture(GL_TEXTURE0));
+ ShaderPipeline::drawTexture(texture, coordinates);
+}
+#endif // !USE_FORCED_GLES
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/extensions.cpp b/backends/graphics/opengl/pipelines/clut8.h
index 4482ef82b5..16724e4652 100644
--- a/backends/graphics/opengl/extensions.cpp
+++ b/backends/graphics/opengl/pipelines/clut8.h
@@ -20,29 +20,27 @@
*
*/
-#include "backends/graphics/opengl/extensions.h"
-#include "backends/graphics/opengl/opengl-sys.h"
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_CLUT8_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_CLUT8_H
-#include "common/tokenizer.h"
+#include "backends/graphics/opengl/pipelines/shader.h"
namespace OpenGL {
-bool g_extNPOTSupported = false;
+#if !USE_FORCED_GLES
+class CLUT8LookUpPipeline : public ShaderPipeline {
+public:
+ CLUT8LookUpPipeline();
-void initializeGLExtensions() {
- const char *extString = (const char *)glGetString(GL_EXTENSIONS);
+ void setPaletteTexture(const GLTexture *paletteTexture) { _paletteTexture = paletteTexture; }
- // Initialize default state.
- g_extNPOTSupported = false;
+ virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates);
- Common::StringTokenizer tokenizer(extString, " ");
- while (!tokenizer.empty()) {
- Common::String token = tokenizer.nextToken();
-
- if (token == "GL_ARB_texture_non_power_of_two") {
- g_extNPOTSupported = true;
- }
- }
-}
+private:
+ const GLTexture *_paletteTexture;
+};
+#endif // !USE_FORCED_GLES
} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/pipelines/fixed.cpp b/backends/graphics/opengl/pipelines/fixed.cpp
new file mode 100644
index 0000000000..8e3bd7eaee
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/fixed.cpp
@@ -0,0 +1,70 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/pipelines/fixed.h"
+
+namespace OpenGL {
+
+#if !USE_FORCED_GLES2
+void FixedPipeline::activateInternal() {
+ GL_CALL(glDisable(GL_LIGHTING));
+ GL_CALL(glDisable(GL_FOG));
+ GL_CALL(glShadeModel(GL_FLAT));
+ GL_CALL(glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST));
+
+ GL_CALL(glEnableClientState(GL_VERTEX_ARRAY));
+ GL_CALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
+
+#if !USE_FORCED_GLES
+ if (g_context.multitextureSupported) {
+ GL_CALL(glActiveTexture(GL_TEXTURE0));
+ }
+#endif
+ GL_CALL(glEnable(GL_TEXTURE_2D));
+}
+
+void FixedPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
+ GL_CALL(glColor4f(r, g, b, a));
+}
+
+void FixedPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates) {
+ texture.bind();
+
+ GL_CALL(glTexCoordPointer(2, GL_FLOAT, 0, texture.getTexCoords()));
+ GL_CALL(glVertexPointer(2, GL_FLOAT, 0, coordinates));
+ GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+}
+
+void FixedPipeline::setProjectionMatrix(const GLfloat *projectionMatrix) {
+ if (!isActive()) {
+ return;
+ }
+
+ GL_CALL(glMatrixMode(GL_PROJECTION));
+ GL_CALL(glLoadMatrixf(projectionMatrix));
+
+ GL_CALL(glMatrixMode(GL_MODELVIEW));
+ GL_CALL(glLoadIdentity());
+}
+#endif // !USE_FORCED_GLES2
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/fixed.h b/backends/graphics/opengl/pipelines/fixed.h
new file mode 100644
index 0000000000..6bfe140c19
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/fixed.h
@@ -0,0 +1,46 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_FIXED_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_FIXED_H
+
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+
+namespace OpenGL {
+
+#if !USE_FORCED_GLES2
+class FixedPipeline : public Pipeline {
+public:
+ virtual void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+
+ virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates);
+
+ virtual void setProjectionMatrix(const GLfloat *projectionMatrix);
+
+protected:
+ virtual void activateInternal();
+};
+#endif // !USE_FORCED_GLES2
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/pipelines/pipeline.cpp b/backends/graphics/opengl/pipelines/pipeline.cpp
new file mode 100644
index 0000000000..6a59cd28e7
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/pipeline.cpp
@@ -0,0 +1,66 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+#include "backends/graphics/opengl/framebuffer.h"
+
+namespace OpenGL {
+
+Pipeline::Pipeline()
+ : _activeFramebuffer(nullptr), _isActive(false) {
+}
+
+void Pipeline::activate() {
+ _isActive = true;
+
+ if (_activeFramebuffer) {
+ _activeFramebuffer->activate();
+ }
+
+ activateInternal();
+}
+
+void Pipeline::deactivate() {
+ deactivateInternal();
+
+ if (_activeFramebuffer) {
+ _activeFramebuffer->deactivate();
+ }
+
+ _isActive = false;
+}
+
+Framebuffer *Pipeline::setFramebuffer(Framebuffer *framebuffer) {
+ Framebuffer *oldFramebuffer = _activeFramebuffer;
+ if (_isActive && oldFramebuffer) {
+ oldFramebuffer->deactivate();
+ }
+
+ _activeFramebuffer = framebuffer;
+ if (_isActive && _activeFramebuffer) {
+ _activeFramebuffer->activate();
+ }
+
+ return oldFramebuffer;
+}
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/pipeline.h b/backends/graphics/opengl/pipelines/pipeline.h
new file mode 100644
index 0000000000..9f32d33b95
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/pipeline.h
@@ -0,0 +1,126 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_PIPELINE_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_PIPELINE_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+#include "backends/graphics/opengl/texture.h"
+
+namespace OpenGL {
+
+class Framebuffer;
+
+/**
+ * Interface for OpenGL pipeline functionality.
+ *
+ * This encapsulates differences in various rendering pipelines used for
+ * OpenGL, OpenGL ES 1, and OpenGL ES 2.
+ */
+class Pipeline {
+public:
+ Pipeline();
+ virtual ~Pipeline() {}
+
+ /**
+ * Activate the pipeline.
+ *
+ * This sets the OpenGL state to make use of drawing with the given
+ * OpenGL pipeline.
+ */
+ void activate();
+
+ /**
+ * Deactivate the pipeline.
+ */
+ void deactivate();
+
+ /**
+ * Set framebuffer to render to.
+ *
+ * Client is responsible for any memory management related to framebuffer.
+ *
+ * @param framebuffer Framebuffer to activate.
+ * @return Formerly active framebuffer.
+ */
+ Framebuffer *setFramebuffer(Framebuffer *framebuffer);
+
+ /**
+ * Set modulation color.
+ *
+ * @param r Red component in [0,1].
+ * @param g Green component in [0,1].
+ * @param b Blue component in [0,1].
+ * @param a Alpha component in [0,1].
+ */
+ virtual void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) = 0;
+
+ /**
+ * Draw a texture rectangle to the currently active framebuffer.
+ *
+ * @param texture Texture to use for drawing.
+ * @param coordinates x1, y1, x2, y2 coordinates where to draw the texture.
+ */
+ virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates) = 0;
+
+ void drawTexture(const GLTexture &texture, GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
+ const GLfloat coordinates[4*2] = {
+ x, y,
+ x + w, y,
+ x, y + h,
+ x + w, y + h
+ };
+ drawTexture(texture, coordinates);
+ }
+
+ /**
+ * Set the projection matrix.
+ *
+ * This is intended to be only ever be used by Framebuffer subclasses.
+ */
+ virtual void setProjectionMatrix(const GLfloat *projectionMatrix) = 0;
+
+protected:
+ /**
+ * Activate the pipeline.
+ *
+ * This sets the OpenGL state to make use of drawing with the given
+ * OpenGL pipeline.
+ */
+ virtual void activateInternal() = 0;
+
+ /**
+ * Deactivate the pipeline.
+ */
+ virtual void deactivateInternal() {}
+
+ bool isActive() const { return _isActive; }
+
+ Framebuffer *_activeFramebuffer;
+
+private:
+ bool _isActive;
+};
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/pipelines/shader.cpp b/backends/graphics/opengl/pipelines/shader.cpp
new file mode 100644
index 0000000000..a2dabb7c22
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/shader.cpp
@@ -0,0 +1,94 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/pipelines/shader.h"
+#include "backends/graphics/opengl/shader.h"
+#include "backends/graphics/opengl/framebuffer.h"
+
+namespace OpenGL {
+
+#if !USE_FORCED_GLES
+ShaderPipeline::ShaderPipeline(Shader *shader)
+ : _activeShader(shader), _colorAttributes() {
+ _vertexAttribLocation = shader->getAttributeLocation("position");
+ _texCoordAttribLocation = shader->getAttributeLocation("texCoordIn");
+ _colorAttribLocation = shader->getAttributeLocation("blendColorIn");
+
+ assert(_vertexAttribLocation != -1);
+ assert(_texCoordAttribLocation != -1);
+ assert(_colorAttribLocation != -1);
+
+ // One of the attributes needs to be passed through location 0, otherwise
+ // we get no output for GL contexts due to GL compatibility reasons. Let's
+ // check whether this ever happens. If this ever gets hit, we need to
+ // enable location 0 and pass some dummy values through it to fix output.
+ assert( _vertexAttribLocation == 0
+ || _texCoordAttribLocation == 0
+ || _colorAttribLocation == 0);
+}
+
+void ShaderPipeline::activateInternal() {
+ GL_CALL(glEnableVertexAttribArray(_vertexAttribLocation));
+ GL_CALL(glEnableVertexAttribArray(_texCoordAttribLocation));
+ GL_CALL(glEnableVertexAttribArray(_colorAttribLocation));
+
+ if (g_context.multitextureSupported) {
+ GL_CALL(glActiveTexture(GL_TEXTURE0));
+ }
+
+ _activeShader->activate();
+
+ GL_CALL(glVertexAttribPointer(_colorAttribLocation, 4, GL_FLOAT, GL_FALSE, 0, _colorAttributes));
+}
+
+void ShaderPipeline::deactivateInternal() {
+ GL_CALL(glDisableVertexAttribArray(_vertexAttribLocation));
+ GL_CALL(glDisableVertexAttribArray(_texCoordAttribLocation));
+ GL_CALL(glDisableVertexAttribArray(_colorAttribLocation));
+
+ _activeShader->deactivate();
+}
+
+void ShaderPipeline::setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
+ GLfloat *dst = _colorAttributes;
+ for (uint i = 0; i < 4; ++i) {
+ *dst++ = r;
+ *dst++ = g;
+ *dst++ = b;
+ *dst++ = a;
+ }
+}
+
+void ShaderPipeline::drawTexture(const GLTexture &texture, const GLfloat *coordinates) {
+ texture.bind();
+
+ GL_CALL(glVertexAttribPointer(_texCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, texture.getTexCoords()));
+ GL_CALL(glVertexAttribPointer(_vertexAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, coordinates));
+ GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+}
+
+void ShaderPipeline::setProjectionMatrix(const GLfloat *projectionMatrix) {
+ _activeShader->setUniform("projection", new ShaderUniformMatrix44(projectionMatrix));
+}
+#endif // !USE_FORCED_GLES
+
+} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/shader.h b/backends/graphics/opengl/pipelines/shader.h
new file mode 100644
index 0000000000..6159607099
--- /dev/null
+++ b/backends/graphics/opengl/pipelines/shader.h
@@ -0,0 +1,59 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_PIPELINES_SHADER_H
+#define BACKENDS_GRAPHICS_OPENGL_PIPELINES_SHADER_H
+
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+
+namespace OpenGL {
+
+#if !USE_FORCED_GLES
+class Shader;
+
+class ShaderPipeline : public Pipeline {
+public:
+ ShaderPipeline(Shader *shader);
+
+ virtual void setColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+
+ virtual void drawTexture(const GLTexture &texture, const GLfloat *coordinates);
+
+ virtual void setProjectionMatrix(const GLfloat *projectionMatrix);
+
+protected:
+ virtual void activateInternal();
+ virtual void deactivateInternal();
+
+ GLint _vertexAttribLocation;
+ GLint _texCoordAttribLocation;
+ GLint _colorAttribLocation;
+
+ GLfloat _colorAttributes[4*4];
+
+ Shader *const _activeShader;
+};
+#endif // !USE_FORCED_GLES
+
+} // End of namespace OpenGL
+
+#endif
diff --git a/backends/graphics/opengl/shader.cpp b/backends/graphics/opengl/shader.cpp
new file mode 100644
index 0000000000..0b4c677d70
--- /dev/null
+++ b/backends/graphics/opengl/shader.cpp
@@ -0,0 +1,335 @@
+/* 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.
+ *
+ */
+
+#include "backends/graphics/opengl/shader.h"
+
+#if !USE_FORCED_GLES
+
+#include "common/textconsole.h"
+#include "common/util.h"
+
+namespace Common {
+DECLARE_SINGLETON(OpenGL::ShaderManager);
+}
+
+namespace OpenGL {
+
+namespace {
+
+#pragma mark - Builtin Shader Sources -
+
+const char *const g_defaultVertexShader =
+ "attribute vec4 position;\n"
+ "attribute vec2 texCoordIn;\n"
+ "attribute vec4 blendColorIn;\n"
+ "\n"
+ "uniform mat4 projection;\n"
+ "\n"
+ "varying vec2 texCoord;\n"
+ "varying vec4 blendColor;\n"
+ "\n"
+ "void main(void) {\n"
+ "\ttexCoord = texCoordIn;\n"
+ "\tblendColor = blendColorIn;\n"
+ "\tgl_Position = projection * position;\n"
+ "}\n";
+
+const char *const g_defaultFragmentShader =
+ "varying vec2 texCoord;\n"
+ "varying vec4 blendColor;\n"
+ "\n"
+ "uniform sampler2D texture;\n"
+ "\n"
+ "void main(void) {\n"
+ "\tgl_FragColor = blendColor * texture2D(texture, texCoord);\n"
+ "}\n";
+
+const char *const g_lookUpFragmentShader =
+ "varying vec2 texCoord;\n"
+ "varying vec4 blendColor;\n"
+ "\n"
+ "uniform sampler2D texture;\n"
+ "uniform sampler2D palette;\n"
+ "\n"
+ "const float adjustFactor = 255.0 / 256.0 + 1.0 / (2.0 * 256.0);"
+ "\n"
+ "void main(void) {\n"
+ "\tvec4 index = texture2D(texture, texCoord);\n"
+ "\tgl_FragColor = blendColor * texture2D(palette, vec2(index.a * adjustFactor, 0.0));\n"
+ "}\n";
+
+
+// Taken from: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_03#OpenGL_ES_2_portability
+const char *const g_precisionDefines =
+ "#ifdef GL_ES\n"
+ "\t#if defined(GL_FRAGMENT_PRECISION_HIGH) && GL_FRAGMENT_PRECISION_HIGH == 1\n"
+ "\t\tprecision highp float;\n"
+ "\t#else\n"
+ "\t\tprecision mediump float;\n"
+ "\t#endif\n"
+ "#else\n"
+ "\t#define highp\n"
+ "\t#define mediump\n"
+ "\t#define lowp\n"
+ "#endif\n";
+
+} // End of anonymous namespace
+
+#pragma mark - Uniform Values -
+
+void ShaderUniformInteger::set(GLint location) const {
+ GL_CALL(glUniform1i(location, _value));
+}
+
+void ShaderUniformFloat::set(GLint location) const {
+ GL_CALL(glUniform1f(location, _value));
+}
+
+void ShaderUniformMatrix44::set(GLint location) const {
+ GL_CALL(glUniformMatrix4fv(location, 1, GL_FALSE, _matrix));
+}
+
+#pragma mark - Shader Implementation -
+
+Shader::Shader(const Common::String &vertex, const Common::String &fragment)
+ : _vertex(vertex), _fragment(fragment), _isActive(false), _program(0), _uniforms() {
+ recreate();
+}
+
+Shader::~Shader() {
+ // According to extension specification glDeleteObjectARB silently ignores
+ // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus
+ // we do not call it with 0 as parameter to avoid warnings.
+ if (_program) {
+ GL_CALL_SAFE(glDeleteProgram, (_program));
+ }
+}
+
+void Shader::destroy() {
+ // According to extension specification glDeleteObjectARB silently ignores
+ // 0. However, with nVidia drivers this can cause GL_INVALID_VALUE, thus
+ // we do not call it with 0 as parameter to avoid warnings.
+ if (_program) {
+ GL_CALL(glDeleteProgram(_program));
+ _program = 0;
+ }
+}
+
+bool Shader::recreate() {
+ // Make sure any old programs are destroyed properly.
+ destroy();
+
+ GLshader vertexShader = compileShader(_vertex.c_str(), GL_VERTEX_SHADER);
+ if (!vertexShader) {
+ return false;
+ }
+
+ GLshader fragmentShader = compileShader(_fragment.c_str(), GL_FRAGMENT_SHADER);
+ if (!fragmentShader) {
+ GL_CALL(glDeleteShader(vertexShader));
+ return false;
+ }
+
+ GL_ASSIGN(_program, glCreateProgram());
+ if (!_program) {
+ GL_CALL(glDeleteShader(vertexShader));
+ GL_CALL(glDeleteShader(fragmentShader));
+ return false;
+ }
+
+ GL_CALL(glAttachShader(_program, vertexShader));
+ GL_CALL(glAttachShader(_program, fragmentShader));
+
+ GL_CALL(glLinkProgram(_program));
+
+ GL_CALL(glDetachShader(_program, fragmentShader));
+ GL_CALL(glDeleteShader(fragmentShader));
+
+ GL_CALL(glDetachShader(_program, vertexShader));
+ GL_CALL(glDeleteShader(vertexShader));
+
+ GLint result;
+ GL_CALL(glGetProgramiv(_program, GL_LINK_STATUS, &result));
+ if (result == GL_FALSE) {
+ GLint logSize;
+ GL_CALL(glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &logSize));
+
+ GLchar *log = new GLchar[logSize];
+ GL_CALL(glGetProgramInfoLog(_program, logSize, nullptr, log));
+ warning("Could not link shader: \"%s\"", log);
+ delete[] log;
+
+ destroy();
+ return false;
+ }
+
+ // Set program object in case shader is active during recreation.
+ if (_isActive) {
+ GL_CALL(glUseProgram(_program));
+ }
+
+ for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) {
+ i->_value.location = getUniformLocation(i->_key.c_str());
+ i->_value.altered = true;
+ if (_isActive) {
+ i->_value.set();
+ }
+ }
+
+ return true;
+}
+
+void Shader::activate() {
+ // Activate program.
+ GL_CALL(glUseProgram(_program));
+
+ // Reset changed uniform values.
+ for (UniformMap::iterator i = _uniforms.begin(), end = _uniforms.end(); i != end; ++i) {
+ i->_value.set();
+ }
+
+ _isActive = true;
+}
+
+void Shader::deactivate() {
+ _isActive = false;
+}
+
+GLint Shader::getAttributeLocation(const char *name) const {
+ GLint result = -1;
+ GL_ASSIGN(result, glGetAttribLocation(_program, name));
+ return result;
+}
+
+GLint Shader::getUniformLocation(const char *name) const {
+ GLint result = -1;
+ GL_ASSIGN(result, glGetUniformLocation(_program, name));
+ return result;
+}
+
+bool Shader::setUniform(const Common::String &name, ShaderUniformValue *value) {
+ UniformMap::iterator uniformIter = _uniforms.find(name);
+ Uniform *uniform;
+
+ if (uniformIter == _uniforms.end()) {
+ const GLint location = getUniformLocation(name.c_str());
+ if (location == -1) {
+ delete value;
+ return false;
+ }
+
+ uniform = &_uniforms[name];
+ uniform->location = location;
+ } else {
+ uniform = &uniformIter->_value;
+ }
+
+ uniform->value = Common::SharedPtr<ShaderUniformValue>(value);
+ uniform->altered = true;
+ if (_isActive) {
+ uniform->set();
+ }
+
+ return true;
+}
+
+GLshader Shader::compileShader(const char *source, GLenum shaderType) {
+ GLshader handle;
+ GL_ASSIGN(handle, glCreateShader(shaderType));
+ if (!handle) {
+ return 0;
+ }
+
+ const char *const sources[2] = {
+ g_precisionDefines,
+ source
+ };
+
+ GL_CALL(glShaderSource(handle, ARRAYSIZE(sources), sources, nullptr));
+ GL_CALL(glCompileShader(handle));
+
+ GLint result;
+ GL_CALL(glGetShaderiv(handle, GL_COMPILE_STATUS, &result));
+ if (result == GL_FALSE) {
+ GLint logSize;
+ GL_CALL(glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &logSize));
+
+ GLchar *log = new GLchar[logSize];
+ GL_CALL(glGetShaderInfoLog(handle, logSize, nullptr, log));
+ warning("Could not compile shader \"%s\": \"%s\"", source, log);
+ delete[] log;
+
+ GL_CALL(glDeleteShader(handle));
+ return 0;
+ }
+
+ return handle;
+}
+
+ShaderManager::ShaderManager() : _initializeShaders(true) {
+ for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
+ _builtIn[i] = nullptr;
+ }
+}
+
+ShaderManager::~ShaderManager() {
+ for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
+ delete _builtIn[i];
+ }
+}
+
+void ShaderManager::notifyDestroy() {
+ for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
+ _builtIn[i]->destroy();
+ }
+}
+
+void ShaderManager::notifyCreate() {
+ if (_initializeShaders) {
+ _initializeShaders = false;
+
+ _builtIn[kDefault] = new Shader(g_defaultVertexShader, g_defaultFragmentShader);
+ _builtIn[kCLUT8LookUp] = new Shader(g_defaultVertexShader, g_lookUpFragmentShader);
+ _builtIn[kCLUT8LookUp]->setUniform1I("palette", 1);
+
+ for (uint i = 0; i < kMaxUsages; ++i) {
+ _builtIn[i]->setUniform1I("texture", 0);
+ }
+ } else {
+ for (int i = 0; i < ARRAYSIZE(_builtIn); ++i) {
+ _builtIn[i]->recreate();
+ }
+ }
+}
+
+Shader *ShaderManager::query(ShaderUsage shader) const {
+ if (shader == kMaxUsages) {
+ warning("OpenGL: ShaderManager::query used with kMaxUsages");
+ return nullptr;
+ }
+
+ return _builtIn[shader];
+}
+
+} // End of namespace OpenGL
+
+#endif // !USE_FORCED_GLES
diff --git a/backends/graphics/opengl/shader.h b/backends/graphics/opengl/shader.h
new file mode 100644
index 0000000000..ec1e516d14
--- /dev/null
+++ b/backends/graphics/opengl/shader.h
@@ -0,0 +1,288 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_OPENGL_SHADER_H
+#define BACKENDS_GRAPHICS_OPENGL_SHADER_H
+
+#include "backends/graphics/opengl/opengl-sys.h"
+
+#if !USE_FORCED_GLES
+
+#include "common/singleton.h"
+#include "common/hash-str.h"
+#include "common/ptr.h"
+
+namespace OpenGL {
+
+/**
+ * A generic uniform value interface for a shader program.
+ */
+class ShaderUniformValue {
+public:
+ virtual ~ShaderUniformValue() {}
+
+ /**
+ * Setup the the value to the given location.
+ *
+ * @param location Location of the uniform.
+ */
+ virtual void set(GLint location) const = 0;
+};
+
+/**
+ * Integer value for a shader uniform.
+ */
+class ShaderUniformInteger : public ShaderUniformValue {
+public:
+ ShaderUniformInteger(GLint value) : _value(value) {}
+
+ virtual void set(GLint location) const override;
+
+private:
+ const GLint _value;
+};
+
+/**
+ * Float value for a shader uniform.
+ */
+class ShaderUniformFloat : public ShaderUniformValue {
+public:
+ ShaderUniformFloat(GLfloat value) : _value(value) {}
+
+ virtual void set(GLint location) const override;
+
+private:
+ const GLfloat _value;
+};
+
+/**
+ * 4x4 Matrix value for a shader uniform.
+ */
+class ShaderUniformMatrix44 : public ShaderUniformValue {
+public:
+ ShaderUniformMatrix44(const GLfloat *mat44) {
+ memcpy(_matrix, mat44, sizeof(_matrix));
+ }
+
+ virtual void set(GLint location) const override;
+
+private:
+ GLfloat _matrix[4*4];
+};
+
+class Shader {
+public:
+ Shader(const Common::String &vertex, const Common::String &fragment);
+ ~Shader();
+
+ /**
+ * Destroy the shader program.
+ *
+ * This keeps the vertex and fragment shader sources around and thus
+ * allows for recreating the shader on context recreation. It also keeps
+ * the uniform state around.
+ */
+ void destroy();
+
+ /**
+ * Recreate shader program.
+ *
+ * @return true on success, false on failure.
+ */
+ bool recreate();
+
+ /**
+ * Make shader active.
+ */
+ void activate();
+
+ /**
+ * Make shader inactive.
+ */
+ void deactivate();
+
+ /**
+ * Return location for attribute with given name.
+ *
+ * @param name Name of the attribute to look up in the shader.
+ * @return The loctaion of -1 if attribute was not found.
+ */
+ GLint getAttributeLocation(const char *name) const;
+ GLint getAttributeLocation(const Common::String &name) const {
+ return getAttributeLocation(name.c_str());
+ }
+
+ /**
+ * Return location for uniform with given name.
+ *
+ * @param name Name of the uniform to look up in the shader.
+ * @return The location or -1 if uniform was not found.
+ */
+ GLint getUniformLocation(const char *name) const;
+ GLint getUniformLocation(const Common::String &name) const {
+ return getUniformLocation(name.c_str());
+ }
+
+ /**
+ * Bind value to uniform.
+ *
+ * @param name The name of the uniform to be set.
+ * @param value The value to be set.
+ * @return 'false' on error (i.e. uniform unknown or otherwise),
+ * 'true' otherwise.
+ */
+ bool setUniform(const Common::String &name, ShaderUniformValue *value);
+
+ /**
+ * Bind integer value to uniform.
+ *
+ * @param name The name of the uniform to be set.
+ * @param value The value to be set.
+ * @return 'false' on error (i.e. uniform unknown or otherwise),
+ * 'true' otherwise.
+ */
+ bool setUniform1I(const Common::String &name, GLint value) {
+ return setUniform(name, new ShaderUniformInteger(value));
+ }
+protected:
+ /**
+ * Vertex shader sources.
+ */
+ const Common::String _vertex;
+
+ /**
+ * Fragment shader sources.
+ */
+ const Common::String _fragment;
+
+ /**
+ * Whether the shader is active or not.
+ */
+ bool _isActive;
+
+ /**
+ * Shader program handle.
+ */
+ GLprogram _program;
+
+ /**
+ * A uniform descriptor.
+ *
+ * This stores the state of a shader uniform. The state is made up of the
+ * uniform location, whether the state was altered since last set, and the
+ * value of the uniform.
+ */
+ struct Uniform {
+ Uniform() : location(-1), altered(false), value() {}
+ Uniform(GLint loc, ShaderUniformValue *val)
+ : location(loc), altered(true), value(val) {}
+
+ /**
+ * Write uniform value into currently active shader.
+ */
+ void set() {
+ if (altered && value) {
+ value->set(location);
+ altered = false;
+ }
+ }
+
+ /**
+ * The location of the uniform or -1 in case it does not exist.
+ */
+ GLint location;
+
+ /**
+ * Whether the uniform state was aletered since last 'set'.
+ */
+ bool altered;
+
+ /**
+ * The value of the uniform.
+ */
+ Common::SharedPtr<ShaderUniformValue> value;
+ };
+
+ typedef Common::HashMap<Common::String, Uniform> UniformMap;
+
+ /**
+ * Map from uniform name to associated uniform description.
+ */
+ UniformMap _uniforms;
+
+ /**
+ * Compile a vertex or fragment shader.
+ *
+ * @param source Sources to the shader.
+ * @param shaderType Type of shader to compile (GL_FRAGMENT_SHADER_ARB or
+ * GL_VERTEX_SHADER_ARB)
+ * @return The shader object or 0 on failure.
+ */
+ static GLshader compileShader(const char *source, GLenum shaderType);
+};
+
+class ShaderManager : public Common::Singleton<ShaderManager> {
+public:
+ enum ShaderUsage {
+ /** Default shader implementing the GL fixed-function pipeline. */
+ kDefault = 0,
+
+ /** CLUT8 look up shader. */
+ kCLUT8LookUp,
+
+ /** Number of built-in shaders. Should not be used for query. */
+ kMaxUsages
+ };
+
+ /**
+ * Notify shader manager about context destruction.
+ */
+ void notifyDestroy();
+
+ /**
+ * Notify shader manager about context creation.
+ */
+ void notifyCreate();
+
+ /**
+ * Query a built-in shader.
+ */
+ Shader *query(ShaderUsage shader) const;
+
+private:
+ friend class Common::Singleton<SingletonBaseType>;
+ ShaderManager();
+ ~ShaderManager();
+
+ bool _initializeShaders;
+
+ Shader *_builtIn[kMaxUsages];
+};
+
+} // End of namespace OpenGL
+
+/** Shortcut for accessing the font manager. */
+#define ShaderMan (OpenGL::ShaderManager::instance())
+
+#endif // !USE_FORCED_GLES
+
+#endif
diff --git a/backends/graphics/opengl/texture.cpp b/backends/graphics/opengl/texture.cpp
index 7b0b22d630..33598b5488 100644
--- a/backends/graphics/opengl/texture.cpp
+++ b/backends/graphics/opengl/texture.cpp
@@ -21,8 +21,10 @@
*/
#include "backends/graphics/opengl/texture.h"
-#include "backends/graphics/opengl/extensions.h"
-#include "backends/graphics/opengl/debug.h"
+#include "backends/graphics/opengl/shader.h"
+#include "backends/graphics/opengl/pipelines/pipeline.h"
+#include "backends/graphics/opengl/pipelines/clut8.h"
+#include "backends/graphics/opengl/framebuffer.h"
#include "common/rect.h"
#include "common/textconsole.h"
@@ -41,94 +43,140 @@ static GLuint nextHigher2(GLuint v) {
return ++v;
}
-GLint Texture::_maxTextureSize = 0;
-void Texture::queryTextureInformation() {
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_maxTextureSize);
- debug(5, "OpenGL maximum texture size: %d", _maxTextureSize);
+GLTexture::GLTexture(GLenum glIntFormat, GLenum glFormat, GLenum glType)
+ : _glIntFormat(glIntFormat), _glFormat(glFormat), _glType(glType),
+ _width(0), _height(0), _logicalWidth(0), _logicalHeight(0),
+ _texCoords(), _glFilter(GL_NEAREST),
+ _glTexture(0) {
+ create();
}
-Texture::Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format)
- : _glIntFormat(glIntFormat), _glFormat(glFormat), _glType(glType), _format(format), _glFilter(GL_NEAREST),
- _glTexture(0), _textureData(), _userPixelData(), _allDirty(false) {
- recreateInternalTexture();
+GLTexture::~GLTexture() {
+ GL_CALL_SAFE(glDeleteTextures, (1, &_glTexture));
}
-Texture::~Texture() {
- releaseInternalTexture();
- _textureData.free();
+void GLTexture::enableLinearFiltering(bool enable) {
+ if (enable) {
+ _glFilter = GL_LINEAR;
+ } else {
+ _glFilter = GL_NEAREST;
+ }
+
+ bind();
+
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
}
-void Texture::releaseInternalTexture() {
- GLCALL(glDeleteTextures(1, &_glTexture));
+void GLTexture::destroy() {
+ GL_CALL(glDeleteTextures(1, &_glTexture));
_glTexture = 0;
}
-void Texture::recreateInternalTexture() {
+void GLTexture::create() {
// Release old texture name in case it exists.
- releaseInternalTexture();
+ destroy();
// Get a new texture name.
- GLCALL(glGenTextures(1, &_glTexture));
+ GL_CALL(glGenTextures(1, &_glTexture));
// Set up all texture parameters.
- GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
- GLCALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
-
- // In case there is an actual texture setup we reinitialize it.
- if (_textureData.getPixels()) {
+ bind();
+ GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+
+ // If a size is specified, allocate memory for it.
+ if (_width != 0 && _height != 0) {
// Allocate storage for OpenGL texture.
- GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _textureData.w,
- _textureData.h, 0, _glFormat, _glType, NULL));
-
- // Mark dirts such that it will be completely refreshed the next time.
- flagDirty();
+ GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _width, _height,
+ 0, _glFormat, _glType, NULL));
}
}
-void Texture::enableLinearFiltering(bool enable) {
- if (enable) {
- _glFilter = GL_LINEAR;
+void GLTexture::bind() const {
+ GL_CALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+}
+
+void GLTexture::setSize(uint width, uint height) {
+ const uint oldWidth = _width;
+ const uint oldHeight = _height;
+
+ if (!g_context.NPOTSupported) {
+ _width = nextHigher2(width);
+ _height = nextHigher2(height);
} else {
- _glFilter = GL_NEAREST;
+ _width = width;
+ _height = height;
}
- GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+ _logicalWidth = width;
+ _logicalHeight = height;
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _glFilter));
- GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _glFilter));
-}
+ // If a size is specified, allocate memory for it.
+ if (width != 0 && height != 0) {
+ const GLfloat texWidth = (GLfloat)width / _width;
+ const GLfloat texHeight = (GLfloat)height / _height;
-void Texture::allocate(uint width, uint height) {
- uint texWidth = width, texHeight = height;
- if (!g_extNPOTSupported) {
- texWidth = nextHigher2(texWidth);
- texHeight = nextHigher2(texHeight);
- }
+ _texCoords[0] = 0;
+ _texCoords[1] = 0;
- // In case the needed texture dimension changed we will reinitialize the
- // texture.
- if (texWidth != _textureData.w || texHeight != _textureData.h) {
- // Create a buffer for the texture data.
- _textureData.create(texWidth, texHeight, _format);
+ _texCoords[2] = texWidth;
+ _texCoords[3] = 0;
- // Set the texture.
- GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
+ _texCoords[4] = 0;
+ _texCoords[5] = texHeight;
- // Allocate storage for OpenGL texture.
- GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _textureData.w,
- _textureData.h, 0, _glFormat, _glType, NULL));
+ _texCoords[6] = texWidth;
+ _texCoords[7] = texHeight;
+
+ // Allocate storage for OpenGL texture if necessary.
+ if (oldWidth != _width || oldHeight != _height) {
+ bind();
+ GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, _glIntFormat, _width,
+ _height, 0, _glFormat, _glType, NULL));
+ }
}
+}
- // Create a sub-buffer for raw access.
- _userPixelData = _textureData.getSubArea(Common::Rect(width, height));
+void GLTexture::updateArea(const Common::Rect &area, const Graphics::Surface &src) {
+ // Set the texture on the active texture unit.
+ bind();
+
+ // Update the actual texture.
+ // Although we have the area of the texture buffer we want to update we
+ // cannot take advantage of the left/right boundries here because it is
+ // not possible to specify a pitch to glTexSubImage2D. To be precise, with
+ // plain OpenGL we could set GL_UNPACK_ROW_LENGTH to achieve this. However,
+ // OpenGL ES 1.0 does not support GL_UNPACK_ROW_LENGTH. Thus, we are left
+ // with the following options:
+ //
+ // 1) (As we do right now) Simply always update the whole texture lines of
+ // rect changed. This is simplest to implement. In case performance is
+ // really an issue we can think of switching to another method.
+ //
+ // 2) Copy the dirty rect to a temporary buffer and upload that by using
+ // glTexSubImage2D. This is what the Android backend does. It is more
+ // complicated though.
+ //
+ // 3) Use glTexSubImage2D per line changed. This is what the old OpenGL
+ // graphics manager did but it is much slower! Thus, we do not use it.
+ GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, area.top, src.w, area.height(),
+ _glFormat, _glType, src.getBasePtr(0, area.top)));
+}
+
+//
+// Surface
+//
+
+Surface::Surface()
+ : _allDirty(false), _dirtyArea() {
}
-void Texture::copyRectToTexture(uint x, uint y, uint w, uint h, const void *srcPtr, uint srcPitch) {
+void Surface::copyRectToTexture(uint x, uint y, uint w, uint h, const void *srcPtr, uint srcPitch) {
Graphics::Surface *dstSurf = getSurface();
assert(x + w <= dstSurf->w);
assert(y + h <= dstSurf->h);
@@ -159,50 +207,74 @@ void Texture::copyRectToTexture(uint x, uint y, uint w, uint h, const void *srcP
}
}
-void Texture::fill(uint32 color) {
+void Surface::fill(uint32 color) {
Graphics::Surface *dst = getSurface();
dst->fillRect(Common::Rect(dst->w, dst->h), color);
flagDirty();
}
-void Texture::draw(GLfloat x, GLfloat y, GLfloat w, GLfloat h) {
- // Only do any processing when the Texture is initialized.
- if (!_textureData.getPixels()) {
- return;
+Common::Rect Surface::getDirtyArea() const {
+ if (_allDirty) {
+ return Common::Rect(getWidth(), getHeight());
+ } else {
+ return _dirtyArea;
+ }
+}
+
+//
+// Surface implementations
+//
+
+Texture::Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format)
+ : Surface(), _format(format), _glTexture(glIntFormat, glFormat, glType),
+ _textureData(), _userPixelData() {
+}
+
+Texture::~Texture() {
+ _textureData.free();
+}
+
+void Texture::destroy() {
+ _glTexture.destroy();
+}
+
+void Texture::recreate() {
+ _glTexture.create();
+
+ // In case image date exists assure it will be completely refreshed next
+ // time.
+ if (_textureData.getPixels()) {
+ flagDirty();
+ }
+}
+
+void Texture::enableLinearFiltering(bool enable) {
+ _glTexture.enableLinearFiltering(enable);
+}
+
+void Texture::allocate(uint width, uint height) {
+ // Assure the texture can contain our user data.
+ _glTexture.setSize(width, height);
+
+ // In case the needed texture dimension changed we will reinitialize the
+ // texture data buffer.
+ if (_glTexture.getWidth() != _textureData.w || _glTexture.getHeight() != _textureData.h) {
+ // Create a buffer for the texture data.
+ _textureData.create(_glTexture.getWidth(), _glTexture.getHeight(), _format);
}
- // First update any potentional changes.
- updateTexture();
-
- // Set the texture.
- GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
-
- // Calculate the texture rect that will be drawn.
- const GLfloat texWidth = (GLfloat)_userPixelData.w / _textureData.w;
- const GLfloat texHeight = (GLfloat)_userPixelData.h / _textureData.h;
- const GLfloat texcoords[4*2] = {
- 0, 0,
- texWidth, 0,
- 0, texHeight,
- texWidth, texHeight
- };
- GLCALL(glTexCoordPointer(2, GL_FLOAT, 0, texcoords));
-
- // Calculate the screen rect where the texture will be drawn.
- const GLfloat vertices[4*2] = {
- x, y,
- x + w, y,
- x, y + h,
- x + w, y + h
- };
- GLCALL(glVertexPointer(2, GL_FLOAT, 0, vertices));
-
- // Draw the texture to the screen buffer.
- GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
-}
-
-void Texture::updateTexture() {
+ // Create a sub-buffer for raw access.
+ _userPixelData = _textureData.getSubArea(Common::Rect(width, height));
+
+ // The whole texture is dirty after we changed the size. This fixes
+ // multiple texture size changes without any actual update in between.
+ // Without this we might try to write a too big texture into the GL
+ // texture.
+ flagDirty();
+}
+
+void Texture::updateGLTexture() {
if (!isDirty()) {
return;
}
@@ -211,7 +283,7 @@ void Texture::updateTexture() {
// In case we use linear filtering we might need to duplicate the last
// pixel row/column to avoid glitches with filtering.
- if (_glFilter == GL_LINEAR) {
+ if (_glTexture.isLinearFilteringEnabled()) {
if (dirtyArea.right == _userPixelData.w && _userPixelData.w != _textureData.w) {
uint height = dirtyArea.height();
@@ -238,42 +310,12 @@ void Texture::updateTexture() {
}
}
- // Set the texture.
- GLCALL(glBindTexture(GL_TEXTURE_2D, _glTexture));
-
- // Update the actual texture.
- // Although we keep track of the dirty part of the texture buffer we
- // cannot take advantage of the left/right boundries here because it is
- // not possible to specify a pitch to glTexSubImage2D. To be precise, with
- // plain OpenGL we could set GL_UNPACK_ROW_LENGTH to achieve this. However,
- // OpenGL ES 1.0 does not support GL_UNPACK_ROW_LENGTH. Thus, we are left
- // with the following options:
- //
- // 1) (As we do right now) Simply always update the whole texture lines of
- // rect changed. This is simplest to implement. In case performance is
- // really an issue we can think of switching to another method.
- //
- // 2) Copy the dirty rect to a temporary buffer and upload that by using
- // glTexSubImage2D. This is what the Android backend does. It is more
- // complicated though.
- //
- // 3) Use glTexSubImage2D per line changed. This is what the old OpenGL
- // graphics manager did but it is much slower! Thus, we do not use it.
- GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, dirtyArea.top, _textureData.w, dirtyArea.height(),
- _glFormat, _glType, _textureData.getBasePtr(0, dirtyArea.top)));
+ _glTexture.updateArea(dirtyArea, _textureData);
// We should have handled everything, thus not dirty anymore.
clearDirty();
}
-Common::Rect Texture::getDirtyArea() const {
- if (_allDirty) {
- return Common::Rect(_userPixelData.w, _userPixelData.h);
- } else {
- return _dirtyArea;
- }
-}
-
TextureCLUT8::TextureCLUT8(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format)
: Texture(glIntFormat, glFormat, glType, format), _clut8Data(), _palette(new byte[256 * format.bytesPerPixel]) {
memset(_palette, 0, sizeof(byte) * format.bytesPerPixel);
@@ -301,6 +343,25 @@ Graphics::PixelFormat TextureCLUT8::getFormat() const {
return Graphics::PixelFormat::createFormatCLUT8();
}
+void TextureCLUT8::setColorKey(uint colorKey) {
+ // We remove all alpha bits from the palette entry of the color key.
+ // This makes sure its properly handled as color key.
+ const uint32 aMask = (0xFF >> _format.aLoss) << _format.aShift;
+
+ if (_format.bytesPerPixel == 2) {
+ uint16 *palette = (uint16 *)_palette + colorKey;
+ *palette &= ~aMask;
+ } else if (_format.bytesPerPixel == 4) {
+ uint32 *palette = (uint32 *)_palette + colorKey;
+ *palette &= ~aMask;
+ } else {
+ warning("TextureCLUT8::setColorKey: Unsupported pixel depth %d", _format.bytesPerPixel);
+ }
+
+ // A palette changes means we need to refresh the whole surface.
+ flagDirty();
+}
+
namespace {
template<typename ColorType>
inline void convertPalette(ColorType *dst, const byte *src, uint colors, const Graphics::PixelFormat &format) {
@@ -312,14 +373,12 @@ inline void convertPalette(ColorType *dst, const byte *src, uint colors, const G
} // End of anonymous namespace
void TextureCLUT8::setPalette(uint start, uint colors, const byte *palData) {
- const Graphics::PixelFormat &hardwareFormat = getHardwareFormat();
-
- if (hardwareFormat.bytesPerPixel == 2) {
- convertPalette<uint16>((uint16 *)_palette + start, palData, colors, hardwareFormat);
- } else if (hardwareFormat.bytesPerPixel == 4) {
- convertPalette<uint32>((uint32 *)_palette + start, palData, colors, hardwareFormat);
+ if (_format.bytesPerPixel == 2) {
+ convertPalette<uint16>((uint16 *)_palette + start, palData, colors, _format);
+ } else if (_format.bytesPerPixel == 4) {
+ convertPalette<uint32>((uint32 *)_palette + start, palData, colors, _format);
} else {
- warning("TextureCLUT8::setPalette: Unsupported pixel depth: %d", hardwareFormat.bytesPerPixel);
+ warning("TextureCLUT8::setPalette: Unsupported pixel depth: %d", _format.bytesPerPixel);
}
// A palette changes means we need to refresh the whole surface.
@@ -343,7 +402,7 @@ inline void doPaletteLookUp(PixelType *dst, const byte *src, uint width, uint he
}
} // End of anonymous namespace
-void TextureCLUT8::updateTexture() {
+void TextureCLUT8::updateGLTexture() {
if (!isDirty()) {
return;
}
@@ -368,7 +427,223 @@ void TextureCLUT8::updateTexture() {
}
// Do generic handling of updating the texture.
- Texture::updateTexture();
+ Texture::updateGLTexture();
+}
+
+#if !USE_FORCED_GL
+TextureRGB555::TextureRGB555()
+ : Texture(GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)),
+ _rgb555Data() {
+}
+
+TextureRGB555::~TextureRGB555() {
+ _rgb555Data.free();
+}
+
+void TextureRGB555::allocate(uint width, uint height) {
+ Texture::allocate(width, height);
+
+ // We only need to reinitialize our RGB555 surface when the output size
+ // changed.
+ if (width == _rgb555Data.w && height == _rgb555Data.h) {
+ return;
+ }
+
+ _rgb555Data.create(width, height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+}
+
+Graphics::PixelFormat TextureRGB555::getFormat() const {
+ return Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
+}
+
+void TextureRGB555::updateTexture() {
+ if (!isDirty()) {
+ return;
+ }
+
+ // Convert color space.
+ Graphics::Surface *outSurf = Texture::getSurface();
+
+ const Common::Rect dirtyArea = getDirtyArea();
+
+ uint16 *dst = (uint16 *)outSurf->getBasePtr(dirtyArea.left, dirtyArea.top);
+ const uint dstAdd = outSurf->pitch - 2 * dirtyArea.width();
+
+ const uint16 *src = (const uint16 *)_rgb555Data.getBasePtr(dirtyArea.left, dirtyArea.top);
+ const uint srcAdd = _rgb555Data.pitch - 2 * dirtyArea.width();
+
+ for (int height = dirtyArea.height(); height > 0; --height) {
+ for (int width = dirtyArea.width(); width > 0; --width) {
+ const uint16 color = *src++;
+
+ *dst++ = ((color & 0x7C00) << 1) // R
+ | (((color & 0x03E0) << 1) | ((color & 0x0200) >> 4)) // G
+ | (color & 0x001F); // B
+ }
+
+ src = (const uint16 *)((const byte *)src + srcAdd);
+ dst = (uint16 *)((byte *)dst + dstAdd);
+ }
+
+ // Do generic handling of updating the texture.
+ Texture::updateGLTexture();
+}
+#endif // !USE_FORCED_GL
+
+#if !USE_FORCED_GLES
+
+// _clut8Texture needs 8 bits internal precision, otherwise graphics glitches
+// can occur. GL_ALPHA does not have any internal precision requirements.
+// However, in practice (according to fuzzie) it's 8bit. If we run into
+// problems, we need to switch to GL_R8 and GL_RED, but that is only supported
+// for ARB_texture_rg and GLES3+ (EXT_rexture_rg does not support GL_R8).
+TextureCLUT8GPU::TextureCLUT8GPU()
+ : _clut8Texture(GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE),
+ _paletteTexture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE),
+ _target(new TextureTarget()), _clut8Pipeline(new CLUT8LookUpPipeline()),
+ _clut8Vertices(), _clut8Data(), _userPixelData(), _palette(),
+ _paletteDirty(false) {
+ // Allocate space for 256 colors.
+ _paletteTexture.setSize(256, 1);
+
+ // Setup pipeline.
+ _clut8Pipeline->setFramebuffer(_target);
+ _clut8Pipeline->setPaletteTexture(&_paletteTexture);
+ _clut8Pipeline->setColor(1.0f, 1.0f, 1.0f, 1.0f);
+}
+
+TextureCLUT8GPU::~TextureCLUT8GPU() {
+ delete _clut8Pipeline;
+ delete _target;
+ _clut8Data.free();
+}
+
+void TextureCLUT8GPU::destroy() {
+ _clut8Texture.destroy();
+ _paletteTexture.destroy();
+ _target->destroy();
+}
+
+void TextureCLUT8GPU::recreate() {
+ _clut8Texture.create();
+ _paletteTexture.create();
+ _target->create();
+
+ // In case image date exists assure it will be completely refreshed next
+ // time.
+ if (_clut8Data.getPixels()) {
+ flagDirty();
+ _paletteDirty = true;
+ }
+}
+
+void TextureCLUT8GPU::enableLinearFiltering(bool enable) {
+ _target->getTexture()->enableLinearFiltering(enable);
+}
+
+void TextureCLUT8GPU::allocate(uint width, uint height) {
+ // Assure the texture can contain our user data.
+ _clut8Texture.setSize(width, height);
+ _target->setSize(width, height);
+
+ // In case the needed texture dimension changed we will reinitialize the
+ // texture data buffer.
+ if (_clut8Texture.getWidth() != _clut8Data.w || _clut8Texture.getHeight() != _clut8Data.h) {
+ // Create a buffer for the texture data.
+ _clut8Data.create(_clut8Texture.getWidth(), _clut8Texture.getHeight(), Graphics::PixelFormat::createFormatCLUT8());
+ }
+
+ // Create a sub-buffer for raw access.
+ _userPixelData = _clut8Data.getSubArea(Common::Rect(width, height));
+
+ // Setup structures for internal rendering to _glTexture.
+ _clut8Vertices[0] = 0;
+ _clut8Vertices[1] = 0;
+
+ _clut8Vertices[2] = width;
+ _clut8Vertices[3] = 0;
+
+ _clut8Vertices[4] = 0;
+ _clut8Vertices[5] = height;
+
+ _clut8Vertices[6] = width;
+ _clut8Vertices[7] = height;
+
+ // The whole texture is dirty after we changed the size. This fixes
+ // multiple texture size changes without any actual update in between.
+ // Without this we might try to write a too big texture into the GL
+ // texture.
+ flagDirty();
+}
+
+Graphics::PixelFormat TextureCLUT8GPU::getFormat() const {
+ return Graphics::PixelFormat::createFormatCLUT8();
+}
+
+void TextureCLUT8GPU::setColorKey(uint colorKey) {
+ _palette[colorKey * 4 + 3] = 0x00;
+
+ _paletteDirty = true;
+}
+
+void TextureCLUT8GPU::setPalette(uint start, uint colors, const byte *palData) {
+ byte *dst = _palette + start * 4;
+
+ while (colors-- > 0) {
+ memcpy(dst, palData, 3);
+ dst[3] = 0xFF;
+
+ dst += 4;
+ palData += 3;
+ }
+
+ _paletteDirty = true;
+}
+
+const GLTexture &TextureCLUT8GPU::getGLTexture() const {
+ return *_target->getTexture();
+}
+
+void TextureCLUT8GPU::updateGLTexture() {
+ const bool needLookUp = Surface::isDirty() || _paletteDirty;
+
+ // Update CLUT8 texture if necessary.
+ if (Surface::isDirty()) {
+ _clut8Texture.updateArea(getDirtyArea(), _clut8Data);
+ clearDirty();
+ }
+
+ // Update palette if necessary.
+ if (_paletteDirty) {
+ Graphics::Surface palSurface;
+ palSurface.init(256, 1, 256, _palette,
+#ifdef SCUMM_LITTLE_ENDIAN
+ Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24) // ABGR8888
+#else
+ Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0) // RGBA8888
+#endif
+ );
+
+ _paletteTexture.updateArea(Common::Rect(256, 1), palSurface);
+ _paletteDirty = false;
+ }
+
+ // In case any data changed, do color look up and store result in _target.
+ if (needLookUp) {
+ lookUpColors();
+ }
+}
+
+void TextureCLUT8GPU::lookUpColors() {
+ // Setup pipeline to do color look up.
+ Pipeline *oldPipeline = g_context.setPipeline(_clut8Pipeline);
+
+ // Do color look up.
+ g_context.getActivePipeline()->drawTexture(_clut8Texture, _clut8Vertices);
+
+ // Restore old state.
+ g_context.setPipeline(oldPipeline);
}
+#endif // !USE_FORCED_GLES
} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/texture.h b/backends/graphics/opengl/texture.h
index ad70833544..3be09cb9f9 100644
--- a/backends/graphics/opengl/texture.h
+++ b/backends/graphics/opengl/texture.h
@@ -32,115 +32,267 @@
namespace OpenGL {
+class Shader;
+
/**
- * An OpenGL texture wrapper. It automatically takes care of all OpenGL
- * texture handling issues and also provides access to the texture data.
+ * A simple GL texture object abstraction.
+ *
+ * This is used for low-level GL texture handling.
*/
-class Texture {
+class GLTexture {
public:
/**
- * Create a new texture with the specific internal format.
+ * Constrcut a new GL texture object.
*
* @param glIntFormat The internal format to use.
* @param glFormat The input format.
* @param glType The input type.
- * @param format The format used for the texture input.
*/
- Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format);
- virtual ~Texture();
+ GLTexture(GLenum glIntFormat, GLenum glFormat, GLenum glType);
+ ~GLTexture();
+
+ /**
+ * Enable or disable linear texture filtering.
+ *
+ * @param enable true to enable and false to disable.
+ */
+ void enableLinearFiltering(bool enable);
+
+ /**
+ * Test whether linear filtering is enabled.
+ */
+ bool isLinearFilteringEnabled() const { return (_glFilter == GL_LINEAR); }
/**
* Destroy the OpenGL texture name.
*/
- void releaseInternalTexture();
+ void destroy();
+
+ /**
+ * Create the OpenGL texture name.
+ */
+ void create();
+
+ /**
+ * Bind the texture to the active texture unit.
+ */
+ void bind() const;
+
+ /**
+ * Sets the size of the texture in pixels.
+ *
+ * The internal OpenGL texture might have a different size. To query the
+ * actual size use getWidth()/getHeight().
+ *
+ * @param width The desired logical width.
+ * @param height The desired logical height.
+ */
+ void setSize(uint width, uint height);
+
+ /**
+ * Copy image data to the texture.
+ *
+ * @param area The area to update.
+ * @param src Surface for the whole texture containing the pixel data
+ * to upload. Only the area described by area will be
+ * uploaded.
+ */
+ void updateArea(const Common::Rect &area, const Graphics::Surface &src);
/**
- * Create the OpenGL texture name and flag the whole texture as dirty.
+ * Query the GL texture's width.
*/
- void recreateInternalTexture();
+ uint getWidth() const { return _width; }
+
+ /**
+ * Query the GL texture's height.
+ */
+ uint getHeight() const { return _height; }
+
+ /**
+ * Query the logical texture's width.
+ */
+ uint getLogicalWidth() const { return _logicalWidth; }
+
+ /**
+ * Query the logical texture's height.
+ */
+ uint getLogicalHeight() const { return _logicalHeight; }
+
+ /**
+ * Obtain texture coordinates for rectangular drawing.
+ */
+ const GLfloat *getTexCoords() const { return _texCoords; }
+
+ /**
+ * Obtain texture name.
+ *
+ * Beware that the texture name changes whenever create is used.
+ * destroy will invalidate the texture name.
+ */
+ GLuint getGLTexture() const { return _glTexture; }
+private:
+ const GLenum _glIntFormat;
+ const GLenum _glFormat;
+ const GLenum _glType;
+
+ uint _width, _height;
+ uint _logicalWidth, _logicalHeight;
+ GLfloat _texCoords[4*2];
+
+ GLint _glFilter;
+
+ GLuint _glTexture;
+};
+
+/**
+ * Interface for OpenGL implementations of a 2D surface.
+ */
+class Surface {
+public:
+ Surface();
+ virtual ~Surface() {}
+
+ /**
+ * Destroy OpenGL description of surface.
+ */
+ virtual void destroy() = 0;
+
+ /**
+ * Recreate OpenGL description of surface.
+ */
+ virtual void recreate() = 0;
/**
* Enable or disable linear texture filtering.
*
* @param enable true to enable and false to disable.
*/
- void enableLinearFiltering(bool enable);
+ virtual void enableLinearFiltering(bool enable) = 0;
/**
- * Allocate texture space for the desired dimensions. This wraps any
- * handling of requirements for POT textures.
+ * Allocate storage for surface.
*
* @param width The desired logical width.
* @param height The desired logical height.
*/
- virtual void allocate(uint width, uint height);
+ virtual void allocate(uint width, uint height) = 0;
+ /**
+ * Copy image data to the surface.
+ *
+ * The format of the input data needs to match the format returned by
+ * getFormat.
+ *
+ * @param x X coordinate of upper left corner to copy data to.
+ * @param y Y coordinate of upper left corner to copy data to.
+ * @param w Width of the image data to copy.
+ * @param h Height of the image data to copy.
+ * @param src Pointer to image data.
+ * @param srcPitch The number of bytes in a row of the image data.
+ */
void copyRectToTexture(uint x, uint y, uint w, uint h, const void *src, uint srcPitch);
+ /**
+ * Fill the surface with a fixed color.
+ *
+ * @param color Color value in format returned by getFormat.
+ */
void fill(uint32 color);
- void draw(GLfloat x, GLfloat y, GLfloat w, GLfloat h);
-
void flagDirty() { _allDirty = true; }
- bool isDirty() const { return _allDirty || !_dirtyArea.isEmpty(); }
-
- uint getWidth() const { return _userPixelData.w; }
- uint getHeight() const { return _userPixelData.h; }
+ virtual bool isDirty() const { return _allDirty || !_dirtyArea.isEmpty(); }
- /**
- * @return The hardware format of the texture data.
- */
- const Graphics::PixelFormat &getHardwareFormat() const { return _format; }
+ virtual uint getWidth() const = 0;
+ virtual uint getHeight() const = 0;
/**
* @return The logical format of the texture data.
*/
- virtual Graphics::PixelFormat getFormat() const { return _format; }
+ virtual Graphics::PixelFormat getFormat() const = 0;
- virtual Graphics::Surface *getSurface() { return &_userPixelData; }
- virtual const Graphics::Surface *getSurface() const { return &_userPixelData; }
+ virtual Graphics::Surface *getSurface() = 0;
+ virtual const Graphics::Surface *getSurface() const = 0;
/**
- * @return Whether the texture data is using a palette.
+ * @return Whether the surface is having a palette.
*/
virtual bool hasPalette() const { return false; }
+ /**
+ * Set color key for paletted textures.
+ *
+ * This needs to be called after any palette update affecting the color
+ * key. Calling this multiple times will result in multiple color indices
+ * to be treated as color keys.
+ */
+ virtual void setColorKey(uint colorKey) {}
virtual void setPalette(uint start, uint colors, const byte *palData) {}
- virtual void *getPalette() { return 0; }
- virtual const void *getPalette() const { return 0; }
-
/**
- * Query texture related OpenGL information from the context. This only
- * queries the maximum texture size for now.
+ * Update underlying OpenGL texture to reflect current state.
*/
- static void queryTextureInformation();
+ virtual void updateGLTexture() = 0;
/**
- * @return Return the maximum texture dimensions supported.
+ * Obtain underlying OpenGL texture.
*/
- static GLint getMaximumTextureSize() { return _maxTextureSize; }
+ virtual const GLTexture &getGLTexture() const = 0;
protected:
- virtual void updateTexture();
+ void clearDirty() { _allDirty = false; _dirtyArea = Common::Rect(); }
Common::Rect getDirtyArea() const;
private:
- const GLenum _glIntFormat;
- const GLenum _glFormat;
- const GLenum _glType;
+ bool _allDirty;
+ Common::Rect _dirtyArea;
+};
+
+/**
+ * An OpenGL texture wrapper. It automatically takes care of all OpenGL
+ * texture handling issues and also provides access to the texture data.
+ */
+class Texture : public Surface {
+public:
+ /**
+ * Create a new texture with the specific internal format.
+ *
+ * @param glIntFormat The internal format to use.
+ * @param glFormat The input format.
+ * @param glType The input type.
+ * @param format The format used for the texture input.
+ */
+ Texture(GLenum glIntFormat, GLenum glFormat, GLenum glType, const Graphics::PixelFormat &format);
+ virtual ~Texture();
+
+ virtual void destroy();
+
+ virtual void recreate();
+
+ virtual void enableLinearFiltering(bool enable);
+
+ virtual void allocate(uint width, uint height);
+
+ virtual uint getWidth() const { return _userPixelData.w; }
+ virtual uint getHeight() const { return _userPixelData.h; }
+
+ /**
+ * @return The logical format of the texture data.
+ */
+ virtual Graphics::PixelFormat getFormat() const { return _format; }
+
+ virtual Graphics::Surface *getSurface() { return &_userPixelData; }
+ virtual const Graphics::Surface *getSurface() const { return &_userPixelData; }
+
+ virtual void updateGLTexture();
+ virtual const GLTexture &getGLTexture() const { return _glTexture; }
+protected:
const Graphics::PixelFormat _format;
- GLint _glFilter;
- GLuint _glTexture;
+private:
+ GLTexture _glTexture;
Graphics::Surface _textureData;
Graphics::Surface _userPixelData;
-
- bool _allDirty;
- Common::Rect _dirtyArea;
- void clearDirty() { _allDirty = false; _dirtyArea = Common::Rect(); }
-
- static GLint _maxTextureSize;
};
class TextureCLUT8 : public Texture {
@@ -154,21 +306,95 @@ public:
virtual bool hasPalette() const { return true; }
+ virtual void setColorKey(uint colorKey);
virtual void setPalette(uint start, uint colors, const byte *palData);
- virtual void *getPalette() { return _palette; }
- virtual const void *getPalette() const { return _palette; }
-
virtual Graphics::Surface *getSurface() { return &_clut8Data; }
virtual const Graphics::Surface *getSurface() const { return &_clut8Data; }
-protected:
+ virtual void updateGLTexture();
+private:
+ Graphics::Surface _clut8Data;
+ byte *_palette;
+};
+
+#if !USE_FORCED_GL
+class TextureRGB555 : public Texture {
+public:
+ TextureRGB555();
+ virtual ~TextureRGB555();
+
+ virtual void allocate(uint width, uint height);
+
+ virtual Graphics::PixelFormat getFormat() const;
+
+ virtual Graphics::Surface *getSurface() { return &_rgb555Data; }
+ virtual const Graphics::Surface *getSurface() const { return &_rgb555Data; }
+
virtual void updateTexture();
+private:
+ Graphics::Surface _rgb555Data;
+};
+#endif // !USE_FORCED_GL
+
+#if !USE_FORCED_GLES
+class TextureTarget;
+class CLUT8LookUpPipeline;
+
+class TextureCLUT8GPU : public Surface {
+public:
+ TextureCLUT8GPU();
+ virtual ~TextureCLUT8GPU();
+
+ virtual void destroy();
+
+ virtual void recreate();
+ virtual void enableLinearFiltering(bool enable);
+
+ virtual void allocate(uint width, uint height);
+
+ virtual bool isDirty() const { return _paletteDirty || Surface::isDirty(); }
+
+ virtual uint getWidth() const { return _userPixelData.w; }
+ virtual uint getHeight() const { return _userPixelData.h; }
+
+ virtual Graphics::PixelFormat getFormat() const;
+
+ virtual bool hasPalette() const { return true; }
+
+ virtual void setColorKey(uint colorKey);
+ virtual void setPalette(uint start, uint colors, const byte *palData);
+
+ virtual Graphics::Surface *getSurface() { return &_userPixelData; }
+ virtual const Graphics::Surface *getSurface() const { return &_userPixelData; }
+
+ virtual void updateGLTexture();
+ virtual const GLTexture &getGLTexture() const;
+
+ static bool isSupportedByContext() {
+ return g_context.shadersSupported
+ && g_context.multitextureSupported
+ && g_context.framebufferObjectSupported;
+ }
private:
+ void lookUpColors();
+
+ GLTexture _clut8Texture;
+ GLTexture _paletteTexture;
+
+ TextureTarget *_target;
+ CLUT8LookUpPipeline *_clut8Pipeline;
+
+ GLfloat _clut8Vertices[4*2];
+
Graphics::Surface _clut8Data;
- byte *_palette;
+ Graphics::Surface _userPixelData;
+
+ byte _palette[4 * 256];
+ bool _paletteDirty;
};
+#endif // !USE_FORCED_GLES
} // End of namespace OpenGL
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp
index 0d140ee4d7..7ea1860d93 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.cpp
+++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp
@@ -45,6 +45,100 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ // Setup proper SDL OpenGL context creation.
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ OpenGL::ContextType glContextType;
+
+ // Context version 1.4 is choosen arbitrarily based on what most shader
+ // extensions were written against.
+#define DEFAULT_GL_MAJOR 1
+#define DEFAULT_GL_MINOR 4
+
+#define DEFAULT_GLES_MAJOR 1
+#define DEFAULT_GLES_MINOR 1
+
+#define DEFAULT_GLES2_MAJOR 2
+#define DEFAULT_GLES2_MINOR 0
+
+#if USE_FORCED_GL
+ glContextType = OpenGL::kContextGL;
+ _glContextProfileMask = 0;
+ _glContextMajor = DEFAULT_GL_MAJOR;
+ _glContextMinor = DEFAULT_GL_MINOR;
+#elif USE_FORCED_GLES
+ glContextType = OpenGL::kContextGLES;
+ _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES;
+ _glContextMajor = DEFAULT_GLES_MAJOR;
+ _glContextMinor = DEFAULT_GLES_MINOR;
+#elif USE_FORCED_GLES2
+ glContextType = OpenGL::kContextGLES2;
+ _glContextProfileMask = SDL_GL_CONTEXT_PROFILE_ES;
+ _glContextMajor = DEFAULT_GLES2_MAJOR;
+ _glContextMinor = DEFAULT_GLES2_MINOR;
+#else
+ bool noDefaults = false;
+
+ // Obtain the default GL(ES) context SDL2 tries to setup.
+ //
+ // Please note this might not actually be SDL2's defaults when multiple
+ // instances of this object have been created. But that is no issue
+ // because then we already set up what we want to use.
+ //
+ // In case no defaults are given we prefer OpenGL over OpenGL ES.
+ if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &_glContextProfileMask) != 0) {
+ _glContextProfileMask = 0;
+ noDefaults = true;
+ }
+
+ if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &_glContextMajor) != 0) {
+ noDefaults = true;
+ }
+
+ if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &_glContextMinor) != 0) {
+ noDefaults = true;
+ }
+
+ if (noDefaults) {
+ if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) {
+ _glContextMajor = DEFAULT_GLES_MAJOR;
+ _glContextMinor = DEFAULT_GLES_MINOR;
+ } else {
+ _glContextProfileMask = 0;
+ _glContextMajor = DEFAULT_GL_MAJOR;
+ _glContextMinor = DEFAULT_GL_MINOR;
+ }
+ }
+
+ if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_ES) {
+ if (_glContextMajor >= 2) {
+ glContextType = OpenGL::kContextGLES2;
+ } else {
+ glContextType = OpenGL::kContextGLES;
+ }
+ } else if (_glContextProfileMask == SDL_GL_CONTEXT_PROFILE_CORE) {
+ glContextType = OpenGL::kContextGL;
+
+ // Core profile does not allow legacy functionality, which we use.
+ // Thus we request a standard OpenGL context.
+ _glContextProfileMask = 0;
+ _glContextMajor = DEFAULT_GL_MAJOR;
+ _glContextMinor = DEFAULT_GL_MINOR;
+ } else {
+ glContextType = OpenGL::kContextGL;
+ }
+#undef DEFAULT_GL_MAJOR
+#undef DEFAULT_GL_MINOR
+#undef DEFAULT_GLES_MAJOR
+#undef DEFAULT_GLES_MINOR
+#undef DEFAULT_GLES2_MAJOR
+#undef DEFAULT_GLES2_MINOR
+#endif
+
+ setContextType(glContextType);
+#else
+ setContextType(OpenGL::kContextGL);
+#endif
+
// Retrieve a list of working fullscreen modes
#if SDL_VERSION_ATLEAST(2, 0, 0)
const int numModes = SDL_GetNumDisplayModes(0);
@@ -100,6 +194,10 @@ OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint deskt
}
OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() {
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ notifyContextDestroy();
+ SDL_GL_DeleteContext(_glContext);
+#endif
}
void OpenGLSdlGraphicsManager::activateManager() {
@@ -210,20 +308,26 @@ Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormat
// RGBA4444
formats.push_back(Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0));
-#ifndef USE_GLES
+#if !USE_FORCED_GLES && !USE_FORCED_GLES2
+#if !USE_FORCED_GL
+ if (!isGLESContext()) {
+#endif
#ifdef SCUMM_LITTLE_ENDIAN
- // RGBA8888
- formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+ // RGBA8888
+ formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
#else
- // ABGR8888
- formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
+ // ABGR8888
+ formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
+#endif
+#if !USE_FORCED_GL
+ }
+#endif
#endif
- // ARGB8888, this should not be here, but Sword25 requires it. :-/
- formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24));
// RGB555, this is used by SCUMM HE 16 bit games.
+ // This is not natively supported by OpenGL ES implementations, we convert
+ // the pixel format internally.
formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
-#endif
formats.push_back(Graphics::PixelFormat::createFormatCLUT8());
@@ -305,6 +409,10 @@ void OpenGLSdlGraphicsManager::refreshScreen() {
#endif
}
+void *OpenGLSdlGraphicsManager::getProcAddress(const char *name) const {
+ return SDL_GL_GetProcAddress(name);
+}
+
bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
// In case we request a fullscreen mode we will use the mode the user
// has chosen last time or the biggest mode available.
@@ -378,6 +486,11 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
flags |= SDL_WINDOW_RESIZABLE;
}
+ // Request a OpenGL (ES) context we can use.
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, _glContextProfileMask);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, _glContextMajor);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, _glContextMinor);
+
if (!_window->createWindow(width, height, flags)) {
// We treat fullscreen requests as a "hint" for now. This means in
// case it is not available we simply ignore it.
@@ -390,13 +503,6 @@ bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
}
}
-#ifdef USE_GLES
- // SDL2 will create a GLES2 context by default, so this is needed for GLES1-profile
- // functions to work.
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
-#endif
_glContext = SDL_GL_CreateContext(_window->getSDLWindow());
if (!_glContext) {
return false;
diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h
index 1552593575..51edcb4363 100644
--- a/backends/graphics/openglsdl/openglsdl-graphics.h
+++ b/backends/graphics/openglsdl/openglsdl-graphics.h
@@ -67,10 +67,13 @@ protected:
virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
virtual void refreshScreen();
+
+ virtual void *getProcAddress(const char *name) const;
private:
bool setupMode(uint width, uint height);
#if SDL_VERSION_ATLEAST(2, 0, 0)
+ int _glContextProfileMask, _glContextMajor, _glContextMinor;
SDL_GLContext _glContext;
#else
uint32 _lastVideoModeLoad;
diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
index 21345515bc..5b591e77ff 100644
--- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
+++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp
@@ -2047,7 +2047,7 @@ void SurfaceSdlGraphicsManager::undrawMouse() {
return;
if (_mouseBackup.w != 0 && _mouseBackup.h != 0)
- addDirtyRect(x, y - _currentShakePos, _mouseBackup.w, _mouseBackup.h);
+ addDirtyRect(x, y, _mouseBackup.w, _mouseBackup.h);
}
void SurfaceSdlGraphicsManager::drawMouse() {
@@ -2088,9 +2088,7 @@ void SurfaceSdlGraphicsManager::drawMouse() {
// We draw the pre-scaled cursor image, so now we need to adjust for
// scaling, shake position and aspect ratio correction manually.
- if (!_overlayVisible) {
- dst.y += _currentShakePos;
- }
+ dst.y += _currentShakePos;
if (_videoMode.aspectRatioCorrection && !_overlayVisible)
dst.y = real2Aspect(dst.y);
diff --git a/backends/midi/windows.cpp b/backends/midi/windows.cpp
index e2b327ffa7..52a46200cb 100644
--- a/backends/midi/windows.cpp
+++ b/backends/midi/windows.cpp
@@ -185,6 +185,9 @@ MusicDevices WindowsMusicPlugin::getDevices() const {
deviceNames.push_back(tmp.szPname);
}
+ // Limit us to the number of actually retrieved devices.
+ numDevs = deviceNames.size();
+
// Check for non-unique device names. This may happen if someone has devices with identical
// names (e. g. more than one USB device of the exact same hardware type). It seems that this
// does happen in reality sometimes. We generate index numbers for these devices.
diff --git a/backends/module.mk b/backends/module.mk
index 3d412c031a..4c1ca42f06 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -3,6 +3,7 @@ MODULE := backends
MODULE_OBJS := \
base-backend.o \
modular-backend.o \
+ audiocd/audiocd-stream.o \
audiocd/default/default-audiocd.o \
events/default/default-events.o \
fs/abstract-fs.o \
@@ -52,10 +53,16 @@ endif
# OpenGL specific source files.
ifdef USE_OPENGL
MODULE_OBJS += \
+ graphics/opengl/context.o \
graphics/opengl/debug.o \
- graphics/opengl/extensions.o \
+ graphics/opengl/framebuffer.o \
graphics/opengl/opengl-graphics.o \
- graphics/opengl/texture.o
+ graphics/opengl/shader.o \
+ graphics/opengl/texture.o \
+ graphics/opengl/pipelines/clut8.o \
+ graphics/opengl/pipelines/fixed.o \
+ graphics/opengl/pipelines/pipeline.o \
+ graphics/opengl/pipelines/shader.o
endif
# SDL specific source files.
@@ -97,6 +104,7 @@ endif
ifdef MACOSX
MODULE_OBJS += \
+ audiocd/macosx/macosx-audiocd.o \
midi/coreaudio.o \
midi/coremidi.o \
updates/macosx/macosx-updates.o \
@@ -105,14 +113,22 @@ endif
ifdef WIN32
MODULE_OBJS += \
+ audiocd/win32/win32-audiocd.o \
fs/windows/windows-fs.o \
fs/windows/windows-fs-factory.o \
midi/windows.o \
plugins/win32/win32-provider.o \
saves/windows/windows-saves.o \
+ updates/win32/win32-updates.o \
taskbar/win32/win32-taskbar.o
endif
+ifeq ($(BACKEND),androidsdl)
+MODULE_OBJS += \
+ events/androidsdl/androidsdl-events.o \
+ graphics/androidsdl/androidsdl-graphics.o
+endif
+
ifdef AMIGAOS
MODULE_OBJS += \
fs/amigaos4/amigaos4-fs.o \
@@ -128,6 +144,11 @@ MODULE_OBJS += \
events/ps3sdl/ps3sdl-events.o
endif
+ifdef USE_LINUXCD
+MODULE_OBJS += \
+ audiocd/linux/linux-audiocd.o
+endif
+
ifeq ($(BACKEND),tizen)
MODULE_OBJS += \
timer/tizen/timer.o
diff --git a/backends/platform/3ds/3ds.mk b/backends/platform/3ds/3ds.mk
new file mode 100644
index 0000000000..7ab58995f6
--- /dev/null
+++ b/backends/platform/3ds/3ds.mk
@@ -0,0 +1,64 @@
+TARGET := scummvm
+
+APP_TITLE := ScummVM
+APP_DESCRIPTION := Point-and-click adventure game engines
+APP_AUTHOR := ScummVM Team
+APP_ICON := backends/platform/3ds/app/icon.png
+
+APP_RSF := backends/platform/3ds/app/scummvm.rsf
+APP_BANNER_IMAGE:= backends/platform/3ds/app/banner.png
+APP_BANNER_AUDIO:= backends/platform/3ds/app/banner.wav
+
+ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
+CXXFLAGS += -std=gnu++11
+ASFLAGS += -mfloat-abi=hard
+LDFLAGS += -specs=3dsx.specs $(ARCH) -L$(DEVKITPRO)/libctru/lib -L$(DEVKITPRO)/portlibs/3ds/lib
+
+.PHONY: clean_3ds
+
+clean: clean_3ds
+
+clean_3ds:
+ $(RM) $(TARGET).3dsx
+ $(RM) $(TARGET).cia
+
+$(TARGET).smdh: $(APP_ICON)
+ @bannertool makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -i $(APP_ICON) -o $@
+ @echo built ... $(notdir $@)
+
+$(TARGET).3dsx: $(EXECUTABLE) $(TARGET).smdh
+ @3dsxtool $< $@ --smdh=$(TARGET).smdh
+ @echo built ... $(notdir $@)
+
+$(TARGET).bnr: $(APP_BANNER_IMAGE) $(APP_BANNER_AUDIO)
+ @bannertool makebanner -o $@ -i $(APP_BANNER_IMAGE) -a $(APP_BANNER_AUDIO)
+ @echo built ... $(notdir $@)
+
+$(TARGET).cia: $(EXECUTABLE) $(APP_RSF) $(TARGET).smdh $(TARGET).bnr
+ @makerom -f cia -target t -exefslogo -o $@ -elf $(EXECUTABLE) -rsf $(APP_RSF) -banner $(TARGET).bnr -icon $(TARGET).smdh
+ @echo built ... $(notdir $@)
+
+#---------------------------------------------------------------------------------
+# rules for assembling GPU shaders
+#---------------------------------------------------------------------------------
+define shader-as
+ $(eval FILEPATH := $(patsubst %.shbin.o,%.shbin,$@))
+ $(eval FILE := $(patsubst %.shbin.o,%.shbin,$(notdir $@)))
+ picasso -o $(FILEPATH) $1
+ bin2s $(FILEPATH) | $(AS) -o $@
+ echo "extern const u8" `(echo $(FILE) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(FILEPATH) | tr . _)`.h
+ echo "extern const u8" `(echo $(FILE) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(FILEPATH) | tr . _)`.h
+ echo "extern const u32" `(echo $(FILE) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(FILEPATH) | tr . _)`.h
+endef
+
+%.shbin.o : %.v.pica %.g.pica
+ @echo $(notdir $^)
+ @$(call shader-as,$^)
+
+%.shbin.o : %.v.pica
+ @echo $(notdir $<)
+ @$(call shader-as,$<)
+
+%.shbin.o : %.shlist
+ @echo $(notdir $<)
+ @$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file)))
diff --git a/backends/platform/3ds/README b/backends/platform/3ds/README
new file mode 100644
index 0000000000..516e694f64
--- /dev/null
+++ b/backends/platform/3ds/README
@@ -0,0 +1,185 @@
+ScummVM 3DS README
+------------------------------------------------------------------------
+
+Table of Contents:
+------------------
+1.0) Installation
+ * 1.1 3DSX installation
+ * 1.2 CIA installation
+2.0) Controls
+ * 2.1 Default key mappings
+ * 2.2 Hover mode
+ * 2.3 Drag mode
+3.0) Supported Games
+4.0) Compiling
+ * 4.1 Prerequisites
+ * * 4.1.1 Compiling third-party libraries
+ * 4.2 Compiling ScummVM
+ * 4.3 Warning for 3DSX build
+
+
+
+1.0) Installation
+-----------------
+There are two possible formats to be used: 3DSX and CIA (recommended).
+The 3DSX format is exclusively used by the Homebrew Launcher and its derivatives.
+The CIA format can be installed directly to the 3DS home menu and can be launched
+using any CFW (Custom Firmware) of your choice.
+
+Installing the Homebrew Launcher or any CFW is beyond the scope of this README.
+Look elsewhere to see how to install those if you do not already have them set up.
+
+
+1.1) 3DSX installation
+----------------
+The CIA format is recommended for stability and maximum game support. If that is
+not an option, you will need one of a collection of 3DS titles installed on your
+system in order to properly launch ScummVM as a 3DSX. This is because the
+Homebrew Launcher hijacks other processes to run 3DSX homebrew, and ScummVM is a
+particularly large homebrew that can't be launched with the resources provided
+by standard system applications.
+
+You will need one of the following (installed or physically in cart slot):
+
+- Youtube
+- Monster Hunter 4 Ultimate Special Demo
+- Monster Hunter 4 Ultimate
+- Monster Hunter 4G
+- Super Smash Bros. for Nintendo 3DS Demo
+- Super Smash Bros. for Nintendo 3DS Special Demo
+- Super Smash Bros. for Nintendo 3DS
+
+Once you have one of the above, you need to merely extract all ScummVM 3DS files
+to the root of your SD card so that all files reside in the /3ds/scummvm/ directory.
+
+
+1.2) CIA installation
+---------------------
+The CIA format requires a DSP binary dump saved on your SD card as /3ds/dspfirm.cdc
+for proper audio support. You can search online to find software to dump this.
+Not having this file will cause many problems with games that need audio, sometimes
+even crashing, so this is NOT considered optional.
+
+Using any CIA installation software (search elsewhere for that), you need to install
+the scummvm.cia file. Then, just like what is done with the 3DSX installation, you
+need to extract all ScummVM 3DS files (scummvm.cia excluded) to the root of your SD
+card so that all files reside in the /3ds/scummvm/ directory.
+
+
+
+2.0) Controls
+-------------
+
+2.1) Default key mappings
+-------------------------
+The D-Pad and A/B/X/Y buttons have mirrored usage. So they do the same things
+depending on if you're right or left-handed.
+
+| Buttons | Function |
+|------------|--------------------------------|
+| A / D-left | Left-click |
+| X / D-up | Right-click |
+| B / D-down | ESC (skips cutscenes and such) |
+| L | Use virtual keyboard |
+| R | Toggle hover/drag modes |
+| Start | Open game menu |
+| Select | Open 3DS config menu |
+| Circle Pad | Move the cursor |
+
+
+2.2) Hover mode
+---------------
+When you use the touchscreen, you are simulating the mere moving of the mouse. You
+can click only with taps, meaning it is impossible to drag stuff or hold down a
+mouse button without using buttons mapped to right/left-click.
+
+
+2.3) Drag mode
+--------------
+Every time you touch and release the touchscreen, you are simulating the click and
+release of the mouse buttons. At the moment, this is only a left-click.
+
+
+
+3.0) Supported Games
+--------------------
+The full game engine compatibility list can be found here:
+http://scummvm.org/compatibility/
+
+While all the above games should run on the 3DS (report if they do not), there are
+many games which are unplayable due to the lack of CPU speed on the 3DS. So if
+you play any games that run really slow, this is not considered a bug, but rather
+a hardware limitation. Though possible GPU optimizations are always in the works.
+The New 3DS console has much better performance, but there are still many newer and
+high-resolution games that cannot be played. A list of these unplayable games and
+game engines will eventually be listed here.
+
+
+
+4.0) Compiling
+--------------
+
+4.1) Prerequisites
+------------------
+ - devkitARM (presumably with libctru, picasso and such)
+ - citro3d
+ - Optional: You should compile third-party libraries for the 3ds (commonly referred
+ to as portlibs in the devkitPRO community). Some games requires these to operate
+ properly.
+
+
+4.1.1) Compiling third-party libraries
+--------------------------------------
+Most libraries used can be compiled with same commands and configuration flags.
+
+It is assumed that you have these environment variables defined:
+ - DEVKITPRO Your root devkitPro directory
+ - DEVKITARM Your root devkitARM directory (probably same as $DEVKITPRO/devkitARM)
+ - CTRULIB Your root libctru directory (probably same as $DEVKITPRO/libctru)
+
+In the source directory of the library:
+ - $ export PORTLIBS=$DEVKITPRO/portlibs/armv6k
+ - $ export PATH=$DEVKITARM/bin:$PATH
+ - $ export PKG_CONFIG_PATH=$PORTLIBS/lib/pkgconfig
+ - $ export CFLAGS="-g -march=armv6k -mtune=mpcore -mfloat-abi=hard -O2
+ -mword-relocations -ffunction-sections -fdata-sections"
+ - $ export CPPFLAGS="-I$PORTLIBS/include -I$CTRULIB/include"
+ - $ export LDFLAGS="-L$PORTLIBS/lib"
+ - $ mkdir -p $PORTLIBS
+ - $ ./configure --prefix=$PORTLIBS --host=arm-none-eabi --disable-shared
+ --enable-static
+ - $ make
+ - $ make install
+
+Useful libraries (and special config flags needed):
+ - zlib
+ - libpng
+ - libjpeg
+ - freetype2 --without-bzip2 --without-harfbuzz
+ - libmad
+ - tremor
+ - flac --disable-cpplibs --without-flac
+ - faad
+
+
+4.2) Compiling ScummVM
+----------------------
+ - $ ./configure --host=3ds
+ - $ make
+
+Additionally compile to specific formats to be used on the 3ds:
+ - $ make scummvm.3dsx
+ - $ make scummvm.cia
+
+
+4.3) Warning for 3DSX build
+---------------------------
+The above configuration command will include all game engines by default and will
+likely be too massive to run using the 3DSX format. Until dynamic modules are figured
+out, you should configure engines like this for 3DSX builds:
+
+ - $ ./configure --host=3ds --disable-all-engines--enable-engine=scumm-7-8,myst,riven,
+ sword1,sword2,sword25,sci,lure,sky,agi,agos
+
+Choose whatever engines you want, but if the ELF's .text section exceeds ~10MB, it
+won't be playable unless it's a CIA.
diff --git a/backends/platform/3ds/app/banner.png b/backends/platform/3ds/app/banner.png
new file mode 100644
index 0000000000..a3b02150ec
--- /dev/null
+++ b/backends/platform/3ds/app/banner.png
Binary files differ
diff --git a/backends/platform/3ds/app/banner.wav b/backends/platform/3ds/app/banner.wav
new file mode 100644
index 0000000000..e0b684b62f
--- /dev/null
+++ b/backends/platform/3ds/app/banner.wav
Binary files differ
diff --git a/backends/platform/3ds/app/icon.png b/backends/platform/3ds/app/icon.png
new file mode 100644
index 0000000000..07022fbac1
--- /dev/null
+++ b/backends/platform/3ds/app/icon.png
Binary files differ
diff --git a/backends/platform/3ds/app/scummvm.rsf b/backends/platform/3ds/app/scummvm.rsf
new file mode 100644
index 0000000000..a4518949bb
--- /dev/null
+++ b/backends/platform/3ds/app/scummvm.rsf
@@ -0,0 +1,219 @@
+BasicInfo:
+ Title : ScummVM
+ ProductCode : ScummVM
+ Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem
+
+TitleInfo:
+ Category : Application
+ UniqueId : 0xFF321
+
+Option:
+ UseOnSD : true # true if App is to be installed to SD
+ FreeProductCode : true # Removes limitations on ProductCode
+ MediaFootPadding : false # If true CCI files are created with padding
+ EnableCrypt : false # Enables encryption for NCCH and CIA
+ EnableCompress : false # Compresses where applicable (currently only exefs:/.code)
+
+AccessControlInfo:
+ CoreVersion : 2
+
+ # Exheader Format Version
+ DescVersion : 2
+
+ # Minimum Required Kernel Version (below is for 4.5.0)
+ ReleaseKernelMajor : "02"
+ ReleaseKernelMinor : "33"
+
+ # ExtData
+ UseExtSaveData : false # enables ExtData
+ #ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId
+
+ # FS:USER Archive Access Permissions
+ # Uncomment as required
+ FileSystemAccess:
+ #- CategorySystemApplication
+ #- CategoryHardwareCheck
+ #- CategoryFileSystemTool
+ #- Debug
+ #- TwlCardBackup
+ #- TwlNandData
+ #- Boss
+ - DirectSdmc
+ #- Core
+ #- CtrNandRo
+ #- CtrNandRw
+ #- CtrNandRoWrite
+ #- CategorySystemSettings
+ #- CardBoard
+ #- ExportImportIvs
+ #- DirectSdmcWrite
+ #- SwitchCleanup
+ #- SaveDataMove
+ #- Shop
+ #- Shell
+ #- CategoryHomeMenu
+
+ # Process Settings
+ MemoryType : Application # Application/System/Base
+ SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB
+ IdealProcessor : 0
+ AffinityMask : 1
+ Priority : 16
+ MaxCpu : 0 # Let system decide
+ HandleTableSize : 0x200
+ DisableDebug : false
+ EnableForceDebug : false
+ CanWriteSharedPage : true
+ CanUsePrivilegedPriority : false
+ CanUseNonAlphabetAndNumber : true
+ PermitMainFunctionArgument : true
+ CanShareDeviceMemory : true
+ RunnableOnSleep : false
+ SpecialMemoryArrange : true
+
+ # New3DS Exclusive Process Settings
+ SystemModeExt : 124MB # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode
+ CpuSpeed : 804MHz # 268MHz(Default)/804MHz
+ EnableL2Cache : true # false(default)/true
+ CanAccessCore2 : true
+
+ # Virtual Address Mappings
+ IORegisterMapping:
+ - 1ff00000-1ff7ffff # DSP memory
+ MemoryMapping:
+ - 1f000000-1f5fffff:r # VRAM
+
+ # Accessible SVCs, <Name>:<ID>
+ SystemCallAccess:
+ ArbitrateAddress: 34
+ Break: 60
+ CancelTimer: 28
+ ClearEvent: 25
+ ClearTimer: 29
+ CloseHandle: 35
+ ConnectToPort: 45
+ ControlMemory: 1
+ CreateAddressArbiter: 33
+ CreateEvent: 23
+ CreateMemoryBlock: 30
+ CreateMutex: 19
+ CreateSemaphore: 21
+ CreateThread: 8
+ CreateTimer: 26
+ DuplicateHandle: 39
+ ExitProcess: 3
+ ExitThread: 9
+ GetCurrentProcessorNumber: 17
+ GetHandleInfo: 41
+ GetProcessId: 53
+ GetProcessIdOfThread: 54
+ GetProcessIdealProcessor: 6
+ GetProcessInfo: 43
+ GetResourceLimit: 56
+ GetResourceLimitCurrentValues: 58
+ GetResourceLimitLimitValues: 57
+ GetSystemInfo: 42
+ GetSystemTick: 40
+ GetThreadContext: 59
+ GetThreadId: 55
+ GetThreadIdealProcessor: 15
+ GetThreadInfo: 44
+ GetThreadPriority: 11
+ MapMemoryBlock: 31
+ OutputDebugString: 61
+ QueryMemory: 2
+ ReleaseMutex: 20
+ ReleaseSemaphore: 22
+ SendSyncRequest1: 46
+ SendSyncRequest2: 47
+ SendSyncRequest3: 48
+ SendSyncRequest4: 49
+ SendSyncRequest: 50
+ SetThreadPriority: 12
+ SetTimer: 27
+ SignalEvent: 24
+ SleepThread: 10
+ UnmapMemoryBlock: 32
+ WaitSynchronization1: 36
+ WaitSynchronizationN: 37
+ Backdoor: 123
+
+ # Service List
+ # Maximum 34 services (32 if firmware is prior to 9.3.0)
+ ServiceAccessControl:
+ - cfg:u
+ - fs:USER
+ - gsp::Gpu
+ - hid:USER
+ - ndm:u
+ - pxi:dev
+ - APT:U
+ - ac:u
+ - act:u
+ - am:net
+ - boss:U
+ - cam:u
+ - cecd:u
+ - dsp::DSP
+ - frd:u
+ - http:C
+ - ir:USER
+ - ir:u
+ - ir:rst
+ - ldr:ro
+ - mic:u
+ - news:u
+ - nim:aoc
+ - nwm::UDS
+ - ptm:u
+ - qtm:u
+ - soc:U
+ - ssl:C
+ - y2r:u
+ - gsp::Lcd
+
+
+SystemControlInfo:
+ SaveDataSize: 0K
+ RemasterVersion: 0
+ StackSize: 0x40000
+
+ # Modules that run services listed above should be included below
+ # Maximum 48 dependencies
+ # If a module is listed that isn't present on the 3DS, the title will get stuck at the logo (3ds waves)
+ # So act, nfc and qtm are commented for 4.x support. Uncomment if you need these.
+ # <module name>:<module titleid>
+ Dependency:
+ ac: 0x0004013000002402
+ #act: 0x0004013000003802
+ am: 0x0004013000001502
+ boss: 0x0004013000003402
+ camera: 0x0004013000001602
+ cecd: 0x0004013000002602
+ cfg: 0x0004013000001702
+ codec: 0x0004013000001802
+ csnd: 0x0004013000002702
+ dlp: 0x0004013000002802
+ dsp: 0x0004013000001a02
+ friends: 0x0004013000003202
+ gpio: 0x0004013000001b02
+ gsp: 0x0004013000001c02
+ hid: 0x0004013000001d02
+ http: 0x0004013000002902
+ i2c: 0x0004013000001e02
+ ir: 0x0004013000003302
+ mcu: 0x0004013000001f02
+ mic: 0x0004013000002002
+ ndm: 0x0004013000002b02
+ news: 0x0004013000003502
+ #nfc: 0x0004013000004002
+ nim: 0x0004013000002c02
+ nwm: 0x0004013000002d02
+ pdn: 0x0004013000002102
+ ps: 0x0004013000003102
+ ptm: 0x0004013000002202
+ #qtm: 0x0004013020004202
+ ro: 0x0004013000003702
+ socket: 0x0004013000002e02
+ spi: 0x0004013000002302
+ ssl: 0x0004013000002f02
diff --git a/backends/platform/3ds/config.cpp b/backends/platform/3ds/config.cpp
new file mode 100644
index 0000000000..117b979d9f
--- /dev/null
+++ b/backends/platform/3ds/config.cpp
@@ -0,0 +1,87 @@
+/* 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.
+ *
+ */
+
+#include "config.h"
+#include "osystem.h"
+#include "options-dialog.h"
+#include "common/config-manager.h"
+#include <3ds.h>
+
+namespace _3DS {
+
+Config config;
+static Common::String prefix = "3ds_";
+
+static bool confGetBool(Common::String key, bool defaultVal) {
+ if (ConfMan.hasKey(prefix + key))
+ return ConfMan.getBool(prefix + key);
+ return defaultVal;
+}
+
+static void confSetBool(Common::String key, bool val) {
+ ConfMan.setBool(prefix + key, val);
+}
+
+static int confGetInt(Common::String key, int defaultVal) {
+ if (ConfMan.hasKey(prefix + key))
+ return ConfMan.getInt(prefix + key);
+ return defaultVal;
+}
+
+static void confSetInt(Common::String key, int val) {
+ ConfMan.setInt(prefix + key, val);
+}
+
+void loadConfig() {
+ config.showCursor = confGetBool("showcursor", true);
+ config.snapToBorder = confGetBool("snaptoborder", true);
+ config.stretchToFit = confGetBool("stretchtofit", false);
+ config.sensitivity = confGetInt("sensitivity", -5);
+ config.screen = confGetInt("screen", kScreenBoth);
+
+ // Turn off the backlight of any screen not used
+ if (R_SUCCEEDED(gspLcdInit())) {
+ if (config.screen == kScreenTop) {
+ GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_TOP);
+ GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_BOTTOM);
+ } else if (config.screen == kScreenBottom) {
+ GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTTOM);
+ GSPLCD_PowerOffBacklight(GSPLCD_SCREEN_TOP);
+ } else
+ GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
+ gspLcdExit();
+ }
+
+ OSystem_3DS *osys = (OSystem_3DS *)g_system;
+ osys->updateConfig();
+}
+
+void saveConfig() {
+ confSetBool("showcursor", config.showCursor);
+ confSetBool("snaptoborder", config.snapToBorder);
+ confSetBool("stretchtofit", config.stretchToFit);
+ confSetInt("sensitivity", config.sensitivity);
+ confSetInt("screen", config.screen);
+ ConfMan.flushToDisk();
+}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/config.h b/backends/platform/3ds/config.h
new file mode 100644
index 0000000000..c8b75736ad
--- /dev/null
+++ b/backends/platform/3ds/config.h
@@ -0,0 +1,45 @@
+/* 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.
+ *
+ */
+
+#ifndef CONFIG_3DS_H
+#define CONFIG_3DS_H
+
+#include "common/str.h"
+
+namespace _3DS {
+
+struct Config {
+ bool showCursor;
+ bool snapToBorder;
+ bool stretchToFit;
+ int sensitivity;
+ int screen;
+};
+
+extern Config config;
+
+void loadConfig();
+void saveConfig();
+
+} // namespace _3DS
+
+#endif // CONFIG_3DS_H
diff --git a/backends/platform/3ds/gui.cpp b/backends/platform/3ds/gui.cpp
new file mode 100644
index 0000000000..0883d5a102
--- /dev/null
+++ b/backends/platform/3ds/gui.cpp
@@ -0,0 +1,46 @@
+/* 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.
+ *
+ */
+
+#include "backends/platform/3ds/gui.h"
+#include "common/system.h"
+
+StatusMessageDialog* StatusMessageDialog::_opened = 0;
+
+StatusMessageDialog::StatusMessageDialog(const Common::String &message, uint32 duration)
+ : MessageDialog(message, 0, 0) {
+ _timer = g_system->getMillis() + duration;
+ if (_opened)
+ _opened->close();
+ _opened = this;
+}
+
+void StatusMessageDialog::handleTickle() {
+ MessageDialog::handleTickle();
+ if (g_system->getMillis() > _timer)
+ close();
+}
+
+void StatusMessageDialog::close() {
+ GUI::Dialog::close();
+ if (_opened)
+ _opened = 0;
+}
diff --git a/backends/platform/3ds/gui.h b/backends/platform/3ds/gui.h
new file mode 100644
index 0000000000..66c6547139
--- /dev/null
+++ b/backends/platform/3ds/gui.h
@@ -0,0 +1,41 @@
+/* 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.
+ *
+ */
+
+#ifndef GUI_3DS_H
+#define GUI_3DS_H
+
+#include "gui/message.h"
+
+class StatusMessageDialog : public GUI::MessageDialog {
+public:
+ StatusMessageDialog(const Common::String &message, uint32 duration);
+
+ void handleTickle();
+
+protected:
+ virtual void close();
+
+ uint32 _timer;
+ static StatusMessageDialog* _opened;
+};
+
+#endif // GUI_3DS_H
diff --git a/backends/platform/3ds/main.cpp b/backends/platform/3ds/main.cpp
new file mode 100644
index 0000000000..6cc2c5cf5d
--- /dev/null
+++ b/backends/platform/3ds/main.cpp
@@ -0,0 +1,54 @@
+/* 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.
+ *
+ */
+
+#include "osystem.h"
+#include <3ds.h>
+
+int main(int argc, char *argv[]) {
+ // Initialize basic libctru stuff
+ gfxInitDefault();
+ cfguInit();
+ osSetSpeedupEnable(true);
+// consoleInit(GFX_TOP, NULL);
+
+ g_system = new _3DS::OSystem_3DS();
+ assert(g_system);
+
+ // Invoke the actual ScummVM main entry point
+// if (argc > 2)
+// res = scummvm_main(argc-2, &argv[2]);
+// else
+// res = scummvm_main(argc, argv);
+ scummvm_main(0, nullptr);
+
+ delete dynamic_cast<_3DS::OSystem_3DS*>(g_system);
+
+ // Turn on both screen backlights before exiting.
+ if (R_SUCCEEDED(gspLcdInit())) {
+ GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
+ gspLcdExit();
+ }
+
+ cfguExit();
+ gfxExit();
+ return 0;
+}
diff --git a/backends/platform/3ds/module.mk b/backends/platform/3ds/module.mk
new file mode 100644
index 0000000000..3eb15aef81
--- /dev/null
+++ b/backends/platform/3ds/module.mk
@@ -0,0 +1,18 @@
+MODULE := backends/platform/3ds
+
+MODULE_OBJS := \
+ main.o \
+ shader.shbin.o \
+ sprite.o \
+ gui.o \
+ config.o \
+ options-dialog.o \
+ osystem.o \
+ osystem-graphics.o \
+ osystem-audio.o \
+ osystem-events.o
+
+# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
+MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
+OBJS := $(MODULE_OBJS) $(OBJS)
+MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))
diff --git a/backends/platform/3ds/options-dialog.cpp b/backends/platform/3ds/options-dialog.cpp
new file mode 100644
index 0000000000..0f8bfd0c66
--- /dev/null
+++ b/backends/platform/3ds/options-dialog.cpp
@@ -0,0 +1,98 @@
+/* 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.
+ *
+ */
+
+#include "options-dialog.h"
+#include "config.h"
+#include "gui/dialog.h"
+#include "gui/gui-manager.h"
+#include "gui/widgets/list.h"
+#include "gui/widgets/tab.h"
+#include "osystem.h"
+#include "engines/scumm/scumm.h"
+#include "gui/widgets/popup.h"
+
+#include "common/translation.h"
+
+namespace _3DS {
+
+bool optionMenuOpened = false;
+
+OptionsDialog::OptionsDialog() : GUI::Dialog(20, 20, 280, 200) {
+
+ optionMenuOpened = true;
+
+ new GUI::ButtonWidget(this, 120, 180, 72, 16, _("~C~lose"), 0, GUI::kCloseCmd);
+ new GUI::ButtonWidget(this, 200, 180, 72, 16, _("~S~ave"), 0, GUI::kOKCmd);
+
+ _showCursorCheckbox = new GUI::CheckboxWidget(this, 5, 5, 130, 20, _("Show mouse cursor"), 0, 0, 'T');
+ _showCursorCheckbox->setState(config.showCursor);
+
+ _snapToBorderCheckbox = new GUI::CheckboxWidget(this, 5, 22, 130, 20, _("Snap to edges"), 0, 0, 'T');
+ _snapToBorderCheckbox->setState(config.snapToBorder);
+
+ _stretchToFitCheckbox = new GUI::CheckboxWidget(this, 140, 5, 130, 20, _("Stretch to fit"), 0, 0, 'T');
+ _stretchToFitCheckbox->setState(config.stretchToFit);
+
+ new GUI::StaticTextWidget(this, 0, 60, 110, 15, _("Use Screen:"), Graphics::kTextAlignRight);
+ _screenRadioGroup = new GUI::RadiobuttonGroup(this, kScreenRadioGroup);
+ _screenTopRadioWidget = new GUI::RadiobuttonWidget(this, 120, 50, 60, 20, _screenRadioGroup, kScreenTop, _("Top"));
+ _screenBottomRadioWidget = new GUI::RadiobuttonWidget(this, 190, 50, 80, 20, _screenRadioGroup, kScreenBottom, _("Bottom"));
+ _screenBothRadioWidget = new GUI::RadiobuttonWidget(this, 155, 70, 80, 20, _screenRadioGroup, kScreenBoth, _("Both"));
+ _screenRadioGroup->setValue(config.screen);
+
+ new GUI::StaticTextWidget(this, 0, 100, 110, 15, _("C-Pad Sensitivity:"), Graphics::kTextAlignRight);
+ _sensitivity = new GUI::SliderWidget(this, 115, 100, 160, 15, "TODO: Add tooltip", 1);
+ _sensitivity->setMinValue(-15);
+ _sensitivity->setMaxValue(30);
+ _sensitivity->setValue(config.sensitivity);
+ _sensitivity->setFlags(GUI::WIDGET_CLEARBG);
+}
+
+OptionsDialog::~OptionsDialog() {
+ optionMenuOpened = false;
+}
+
+void OptionsDialog::updateConfigManager() {
+ config.showCursor = _showCursorCheckbox->getState();
+ config.snapToBorder = _snapToBorderCheckbox->getState();
+ config.stretchToFit = _stretchToFitCheckbox->getState();
+ config.sensitivity = _sensitivity->getValue();
+ config.screen = _screenRadioGroup->getValue();
+ saveConfig();
+ loadConfig();
+}
+
+void OptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+ switch(cmd) {
+ case GUI::kOKCmd:
+ updateConfigManager();
+ // Fall through
+ case GUI::kCloseCmd:
+ close();
+ break;
+ default:
+ Dialog::handleCommand(sender, cmd, data);
+ break;
+ }
+}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/options-dialog.h b/backends/platform/3ds/options-dialog.h
new file mode 100644
index 0000000000..6673b88e7b
--- /dev/null
+++ b/backends/platform/3ds/options-dialog.h
@@ -0,0 +1,70 @@
+/* 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.
+ *
+ */
+
+#ifndef OPTIONS_DIALOG_3DS_H
+#define OPTIONS_DIALOG_3DS_H
+
+
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "gui/object.h"
+#include "gui/widget.h"
+#include "gui/dialog.h"
+#include "gui/widgets/tab.h"
+#include "scumm/dialogs.h"
+
+namespace _3DS {
+
+enum {
+ kSave = 0x10000000,
+ kScreenRadioGroup,
+ kScreenTop,
+ kScreenBottom,
+ kScreenBoth,
+};
+
+extern bool optionMenuOpened;
+
+class OptionsDialog : public GUI::Dialog {
+
+public:
+ OptionsDialog();
+ ~OptionsDialog();
+
+protected:
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ void updateConfigManager();
+
+ GUI::SliderWidget *_sensitivity;
+ GUI::CheckboxWidget *_showCursorCheckbox;
+ GUI::CheckboxWidget *_snapToBorderCheckbox;
+ GUI::CheckboxWidget *_stretchToFitCheckbox;
+
+ GUI::RadiobuttonGroup *_screenRadioGroup;
+ GUI::RadiobuttonWidget *_screenTopRadioWidget;
+ GUI::RadiobuttonWidget *_screenBottomRadioWidget;
+ GUI::RadiobuttonWidget *_screenBothRadioWidget;
+};
+
+} // namespace _3DS
+
+#endif // OPTIONS_DIALOG_3DS_H
diff --git a/backends/platform/3ds/osystem-audio.cpp b/backends/platform/3ds/osystem-audio.cpp
new file mode 100644
index 0000000000..17e419c36d
--- /dev/null
+++ b/backends/platform/3ds/osystem-audio.cpp
@@ -0,0 +1,110 @@
+/* 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.
+ *
+ */
+
+#include "osystem.h"
+#include "audio/mixer.h"
+
+namespace _3DS {
+
+static bool hasAudio = false;
+
+static void audioThreadFunc(void *arg) {
+ Audio::MixerImpl *mixer = (Audio::MixerImpl *)arg;
+ OSystem_3DS *osys = (OSystem_3DS *)g_system;
+
+ int i;
+ const int channel = 0;
+ int bufferIndex = 0;
+ const int bufferCount = 3;
+ const int bufferSize = 80000; // Can't be too small, based on delayMillis duration
+ const int sampleRate = mixer->getOutputRate();
+ int sampleLen = 0;
+ uint32 lastTime = osys->getMillis(true);
+ uint32 time = lastTime;
+ ndspWaveBuf buffers[bufferCount];
+
+ for (i = 0; i < bufferCount; ++i) {
+ memset(&buffers[i], 0, sizeof(ndspWaveBuf));
+ buffers[i].data_vaddr = linearAlloc(bufferSize);
+ buffers[i].looping = false;
+ buffers[i].status = NDSP_WBUF_FREE;
+ }
+
+ ndspChnReset(channel);
+ ndspChnSetInterp(channel, NDSP_INTERP_LINEAR);
+ ndspChnSetRate(channel, sampleRate);
+ ndspChnSetFormat(channel, NDSP_FORMAT_STEREO_PCM16);
+
+ while (!osys->exiting) {
+ osys->delayMillis(100); // Note: Increasing the delay requires a bigger buffer
+
+ time = osys->getMillis(true);
+ sampleLen = (time - lastTime) * 22 * 4; // sampleRate / 1000 * channelCount * sizeof(int16);
+ lastTime = time;
+
+ if (!osys->sleeping && sampleLen > 0) {
+ bufferIndex++;
+ bufferIndex %= bufferCount;
+ ndspWaveBuf *buf = &buffers[bufferIndex];
+
+ buf->nsamples = mixer->mixCallback(buf->data_adpcm, sampleLen);
+ if (buf->nsamples > 0) {
+ DSP_FlushDataCache(buf->data_vaddr, bufferSize);
+ ndspChnWaveBufAdd(channel, buf);
+ }
+ }
+ }
+
+ for (i = 0; i < bufferCount; ++i)
+ linearFree(buffers[i].data_pcm8);
+}
+
+void OSystem_3DS::initAudio() {
+ _mixer = new Audio::MixerImpl(this, 22050);
+
+ hasAudio = R_SUCCEEDED(ndspInit());
+ _mixer->setReady(false);
+
+ if (hasAudio) {
+ s32 prio = 0;
+ svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+ audioThread = threadCreate(&audioThreadFunc, _mixer, 32 * 1048, prio - 1, -2, false);
+ }
+}
+
+void OSystem_3DS::destroyAudio() {
+ if (hasAudio) {
+ threadJoin(audioThread, U64_MAX);
+ threadFree(audioThread);
+ ndspExit();
+ }
+
+ delete _mixer;
+ _mixer = 0;
+}
+
+Audio::Mixer *OSystem_3DS::getMixer() {
+ assert(_mixer);
+ return _mixer;
+}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
new file mode 100644
index 0000000000..ae8a9b8b2b
--- /dev/null
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -0,0 +1,302 @@
+/* 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.
+ *
+ */
+
+#include "backends/timer/default/default-timer.h"
+#include "engines/engine.h"
+#include "gui.h"
+#include "options-dialog.h"
+#include "config.h"
+#include "osystem.h"
+
+namespace _3DS {
+
+static Common::Mutex *eventMutex;
+static InputMode inputMode = MODE_DRAG;
+static aptHookCookie cookie;
+static bool optionMenuOpening = false;
+static Common::String messageOSD;
+static bool showMessageOSD = false;
+
+static void pushEventQueue(Common::Queue<Common::Event> *queue, Common::Event &event) {
+ Common::StackLock lock(*eventMutex);
+ queue->push(event);
+}
+
+static void eventThreadFunc(void *arg) {
+ OSystem_3DS *osys = (OSystem_3DS *)g_system;
+ auto eventQueue = (Common::Queue<Common::Event> *)arg;
+
+ uint32 touchStartTime = osys->getMillis();
+ touchPosition lastTouch = {0, 0};
+ bool isRightClick = false;
+ float cursorX = 0;
+ float cursorY = 0;
+ float cursorDeltaX = 0;
+ float cursorDeltaY = 0;
+ int circleDeadzone = 20;
+ int borderSnapZone = 6;
+ Common::Event event;
+
+ while (!osys->exiting) {
+ do {
+ osys->delayMillis(10);
+ } while (osys->sleeping && !osys->exiting);
+
+ hidScanInput();
+ touchPosition touch;
+ circlePosition circle;
+ u32 held = hidKeysHeld();
+ u32 keysPressed = hidKeysDown();
+ u32 keysReleased = hidKeysUp();
+
+ // C-Pad used to control the cursor
+ hidCircleRead(&circle);
+ if (circle.dx < circleDeadzone && circle.dx > -circleDeadzone)
+ circle.dx = 0;
+ if (circle.dy < circleDeadzone && circle.dy > -circleDeadzone)
+ circle.dy = 0;
+ cursorDeltaX = (0.0002f + config.sensitivity / 100000.f) * circle.dx * abs(circle.dx);
+ cursorDeltaY = (0.0002f + config.sensitivity / 100000.f) * circle.dy * abs(circle.dy);
+
+ // Touch screen events
+ if (held & KEY_TOUCH) {
+ hidTouchRead(&touch);
+ if (config.snapToBorder) {
+ if (touch.px < borderSnapZone)
+ touch.px = 0;
+ if (touch.px > 319 - borderSnapZone)
+ touch.px = 319;
+ if (touch.py < borderSnapZone)
+ touch.py = 0;
+ if (touch.py > 239 - borderSnapZone)
+ touch.py = 239;
+ }
+ cursorX = touch.px;
+ cursorY = touch.py;
+ osys->transformPoint(touch);
+
+ osys->warpMouse(touch.px, touch.py);
+ event.mouse.x = touch.px;
+ event.mouse.y = touch.py;
+
+ if (keysPressed & KEY_TOUCH) {
+ touchStartTime = osys->getMillis();
+ isRightClick = (held & KEY_X || held & KEY_DUP);
+ if (inputMode == MODE_DRAG) {
+ event.type = isRightClick ? Common::EVENT_RBUTTONDOWN : Common::EVENT_LBUTTONDOWN;
+ pushEventQueue(eventQueue, event);
+ }
+ } else if (touch.px != lastTouch.px || touch.py != lastTouch.py) {
+ event.type = Common::EVENT_MOUSEMOVE;
+ pushEventQueue(eventQueue, event);
+ }
+
+ lastTouch = touch;
+ } else if (keysReleased & KEY_TOUCH) {
+ event.mouse.x = lastTouch.px;
+ event.mouse.y = lastTouch.py;
+ if (inputMode == MODE_DRAG) {
+ event.type = isRightClick ? Common::EVENT_RBUTTONUP : Common::EVENT_LBUTTONUP;
+ pushEventQueue(eventQueue, event);
+ } else if (osys->getMillis() - touchStartTime < 200) {
+ // Process click in MODE_HOVER
+ event.type = Common::EVENT_MOUSEMOVE;
+ pushEventQueue(eventQueue, event);
+ event.type = isRightClick ? Common::EVENT_RBUTTONDOWN : Common::EVENT_LBUTTONDOWN;
+ pushEventQueue(eventQueue, event);
+ event.type = isRightClick ? Common::EVENT_RBUTTONUP : Common::EVENT_LBUTTONUP;
+ pushEventQueue(eventQueue, event);
+ }
+ } else if (cursorDeltaX != 0 || cursorDeltaY != 0) {
+ cursorX += cursorDeltaX;
+ cursorY -= cursorDeltaY;
+ if (cursorX < 0) cursorX = 0;
+ if (cursorY < 0) cursorY = 0;
+ if (cursorX > 320) cursorX = 320;
+ if (cursorY > 240) cursorY = 240;
+ lastTouch.px = cursorX;
+ lastTouch.py = cursorY;
+ osys->transformPoint(lastTouch);
+ osys->warpMouse(lastTouch.px, lastTouch.py);
+ event.mouse.x = lastTouch.px;
+ event.mouse.y = lastTouch.py;
+ event.type = Common::EVENT_MOUSEMOVE;
+ pushEventQueue(eventQueue, event);
+ }
+
+ // Button events
+ if (keysPressed & KEY_R) {
+ if (inputMode == MODE_DRAG) {
+ inputMode = MODE_HOVER;
+ osys->displayMessageOnOSD("Hover Mode");
+ } else {
+ inputMode = MODE_DRAG;
+ osys->displayMessageOnOSD("Drag Mode");
+ }
+ }
+ if (keysPressed & KEY_A || keysPressed & KEY_DLEFT || keysReleased & KEY_A || keysReleased & KEY_DLEFT) {
+ // SIMULATE LEFT CLICK
+ event.mouse.x = lastTouch.px;
+ event.mouse.y = lastTouch.py;
+ if (keysPressed & KEY_A || keysPressed & KEY_DLEFT)
+ event.type = Common::EVENT_LBUTTONDOWN;
+ else
+ event.type = Common::EVENT_LBUTTONUP;
+ pushEventQueue(eventQueue, event);
+ }
+ if (keysPressed & KEY_X || keysPressed & KEY_DUP || keysReleased & KEY_X || keysReleased & KEY_DUP) {
+ // SIMULATE RIGHT CLICK
+ event.mouse.x = lastTouch.px;
+ event.mouse.y = lastTouch.py;
+ if (keysPressed & KEY_X || keysPressed & KEY_DUP)
+ event.type = Common::EVENT_RBUTTONDOWN;
+ else
+ event.type = Common::EVENT_RBUTTONUP;
+ pushEventQueue(eventQueue, event);
+ }
+ if (keysPressed & KEY_L) {
+ event.type = Common::EVENT_VIRTUAL_KEYBOARD;
+ pushEventQueue(eventQueue, event);
+ }
+ if (keysPressed & KEY_START) {
+ event.type = Common::EVENT_MAINMENU;
+ pushEventQueue(eventQueue, event);
+ }
+ if (keysPressed & KEY_SELECT) {
+ if (!optionMenuOpened)
+ optionMenuOpening = true;
+ }
+ if (keysPressed & KEY_B || keysReleased & KEY_B || keysPressed & KEY_DDOWN || keysReleased & KEY_DDOWN) {
+ if (keysPressed & KEY_B || keysPressed & KEY_DDOWN)
+ event.type = Common::EVENT_KEYDOWN;
+ else
+ event.type = Common::EVENT_KEYUP;
+ event.kbd.keycode = Common::KEYCODE_ESCAPE;
+ event.kbd.ascii = Common::ASCII_ESCAPE;
+ event.kbd.flags = 0;
+ pushEventQueue(eventQueue, event);
+ }
+
+ // TODO: EVENT_PREDICTIVE_DIALOG
+ // EVENT_SCREEN_CHANGED
+ }
+}
+
+static void aptHookFunc(APT_HookType hookType, void *param) {
+ OSystem_3DS *osys = (OSystem_3DS *)g_system;
+
+ switch (hookType) {
+ case APTHOOK_ONSUSPEND:
+ case APTHOOK_ONSLEEP:
+ if (g_engine)
+ g_engine->pauseEngine(true);
+ osys->sleeping = true;
+ if (R_SUCCEEDED(gspLcdInit())) {
+ GSPLCD_PowerOnBacklight(GSPLCD_SCREEN_BOTH);
+ gspLcdExit();
+ }
+ break;
+ case APTHOOK_ONRESTORE:
+ case APTHOOK_ONWAKEUP:
+ if (g_engine)
+ g_engine->pauseEngine(false);
+ osys->sleeping = false;
+ loadConfig();
+ break;
+ default: {
+ Common::StackLock lock(*eventMutex);
+ Common::Event event;
+ event.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(event);
+ }
+ }
+}
+
+static void timerThreadFunc(void *arg) {
+ OSystem_3DS *osys = (OSystem_3DS *)arg;
+ DefaultTimerManager *tm = (DefaultTimerManager *)osys->getTimerManager();
+ while (!osys->exiting) {
+ g_system->delayMillis(10);
+ tm->handler();
+ }
+}
+
+void OSystem_3DS::initEvents() {
+ eventMutex = new Common::Mutex();
+ s32 prio = 0;
+ svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+ _timerThread = threadCreate(&timerThreadFunc, this, 32 * 1024, prio - 1, -2, false);
+ _eventThread = threadCreate(&eventThreadFunc, &_eventQueue, 32 * 1024, prio - 1, -2, false);
+
+ aptHook(&cookie, aptHookFunc, this);
+}
+
+void OSystem_3DS::destroyEvents() {
+ threadJoin(_timerThread, U64_MAX);
+ threadFree(_timerThread);
+
+ threadJoin(_eventThread, U64_MAX);
+ threadFree(_eventThread);
+ delete eventMutex;
+}
+
+void OSystem_3DS::transformPoint(touchPosition &point) {
+ if (!_overlayVisible) {
+ point.px = static_cast<float>(point.px) / _gameBottomTexture.getScaleX() - _gameBottomX;
+ point.py = static_cast<float>(point.py) / _gameBottomTexture.getScaleY() - _gameBottomY;
+ }
+}
+
+void OSystem_3DS::displayMessageOnOSD(const char *msg) {
+ messageOSD = msg;
+ showMessageOSD = true;
+}
+
+bool OSystem_3DS::pollEvent(Common::Event &event) {
+ if (showMessageOSD) {
+ showMessageOSD = false;
+ StatusMessageDialog dialog(messageOSD, 800);
+ dialog.runModal();
+ }
+
+ aptMainLoop(); // Call apt hook when necessary
+
+ if (optionMenuOpening) {
+ optionMenuOpening = false;
+ OptionsDialog dialog;
+ if (g_engine)
+ g_engine->pauseEngine(true);
+ dialog.runModal();
+ if (g_engine)
+ g_engine->pauseEngine(false);
+ }
+
+ Common::StackLock lock(*eventMutex);
+
+ if (_eventQueue.empty())
+ return false;
+
+ event = _eventQueue.pop();
+ return true;
+}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
new file mode 100644
index 0000000000..0cfd70c9cd
--- /dev/null
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -0,0 +1,517 @@
+/* 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.
+ *
+ */
+
+#include "backends/platform/3ds/osystem.h"
+#include "backends/platform/3ds/shader_shbin.h"
+#include "common/rect.h"
+#include "options-dialog.h"
+#include "config.h"
+
+// Used to transfer the final rendered display to the framebuffer
+#define DISPLAY_TRANSFER_FLAGS \
+ (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | \
+ GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
+ GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
+ GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+
+namespace _3DS {
+
+void OSystem_3DS::initGraphics() {
+ _pfGame = Graphics::PixelFormat::createFormatCLUT8();
+ _pfGameTexture = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+
+ C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
+
+ // Initialize the render targets
+ _renderTargetTop =
+ C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
+ C3D_RenderTargetSetClear(_renderTargetTop, C3D_CLEAR_ALL, 0x0000000, 0);
+ C3D_RenderTargetSetOutput(_renderTargetTop, GFX_TOP, GFX_LEFT,
+ DISPLAY_TRANSFER_FLAGS);
+
+ _renderTargetBottom =
+ C3D_RenderTargetCreate(240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
+ C3D_RenderTargetSetClear(_renderTargetBottom, C3D_CLEAR_ALL, 0x00000000, 0);
+ C3D_RenderTargetSetOutput(_renderTargetBottom, GFX_BOTTOM, GFX_LEFT,
+ DISPLAY_TRANSFER_FLAGS);
+
+ // Load and bind simple default shader (shader.v.pica)
+ _dvlb = DVLB_ParseFile((u32*)shader_shbin, shader_shbin_size);
+ shaderProgramInit(&_program);
+ shaderProgramSetVsh(&_program, &_dvlb->DVLE[0]);
+ C3D_BindProgram(&_program);
+
+ _projectionLocation = shaderInstanceGetUniformLocation(_program.vertexShader, "projection");
+ _modelviewLocation = shaderInstanceGetUniformLocation(_program.vertexShader, "modelView");
+
+ C3D_AttrInfo *attrInfo = C3D_GetAttrInfo();
+ AttrInfo_Init(attrInfo);
+ AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
+ AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord
+
+ Mtx_OrthoTilt(&_projectionTop, 0.0, 400.0, 240.0, 0.0, 0.0, 1.0);
+ Mtx_OrthoTilt(&_projectionBottom, 0.0, 320.0, 240.0, 0.0, 0.0, 1.0);
+
+ C3D_TexEnv *env = C3D_GetTexEnv(0);
+ C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, 0, 0);
+ C3D_TexEnvOp(env, C3D_Both, 0, 0, 0);
+ C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
+
+ C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL);
+ C3D_CullFace(GPU_CULL_NONE);
+}
+
+void OSystem_3DS::destroyGraphics() {
+ _gameScreen.free();
+ _gameTopTexture.free();
+ _gameBottomTexture.free();
+ _overlay.free();
+
+ shaderProgramFree(&_program);
+ DVLB_Free(_dvlb);
+
+ C3D_RenderTargetDelete(_renderTargetTop);
+ C3D_RenderTargetDelete(_renderTargetBottom);
+
+ C3D_Fini();
+}
+
+bool OSystem_3DS::hasFeature(OSystem::Feature f) {
+ return (f == OSystem::kFeatureCursorPalette ||
+ f == OSystem::kFeatureOverlaySupportsAlpha);
+}
+
+void OSystem_3DS::setFeatureState(OSystem::Feature f, bool enable) {
+ switch (f) {
+ case OSystem::kFeatureCursorPalette:
+ _cursorPaletteEnabled = enable;
+ flushCursor();
+ break;
+ default:
+ break;
+ }
+}
+
+bool OSystem_3DS::getFeatureState(OSystem::Feature f) {
+ switch (f) {
+ case OSystem::kFeatureCursorPalette:
+ return _cursorPaletteEnabled;
+ default:
+ return false;
+ }
+}
+
+const OSystem::GraphicsMode *
+OSystem_3DS::getSupportedGraphicsModes() const {
+ return s_graphicsModes;
+}
+
+int OSystem_3DS::getDefaultGraphicsMode() const {
+ return GFX_LINEAR;
+}
+
+bool OSystem_3DS::setGraphicsMode(int mode) {
+ return true;
+}
+
+void OSystem_3DS::resetGraphicsScale() {
+ debug("resetGraphicsScale");
+}
+
+int OSystem_3DS::getGraphicsMode() const {
+ return GFX_LINEAR;
+}
+void OSystem_3DS::initSize(uint width, uint height,
+ const Graphics::PixelFormat *format) {
+ debug("3ds initsize w:%d h:%d", width, height);
+ _gameWidth = width;
+ _gameHeight = height;
+ _gameTopTexture.create(width, height, _pfGameTexture);
+ _overlay.create(getOverlayWidth(), getOverlayHeight(), _pfGameTexture);
+
+ if (format) {
+ debug("pixelformat: %d %d %d %d %d", format->bytesPerPixel, format->rBits(), format->gBits(), format->bBits(), format->aBits());;
+ _pfGame = *format;
+ }
+
+ _gameScreen.create(width, height, _pfGame);
+
+ _focusDirty = true;
+ _focusRect = Common::Rect(_gameWidth, _gameHeight);
+
+ updateSize();
+}
+
+void OSystem_3DS::updateSize() {
+ if (config.stretchToFit) {
+ _gameTopX = _gameTopY = _gameBottomX = _gameBottomY = 0;
+ _gameTopTexture.setScale(400.f / _gameWidth, 240.f / _gameHeight);
+ _gameBottomTexture.setScale(320.f / _gameWidth, 240.f / _gameHeight);
+ } else {
+ float ratio = static_cast<float>(_gameWidth) / _gameHeight;
+
+ if (ratio > 400.f / 240.f) {
+ float r = 400.f / _gameWidth;
+ _gameTopTexture.setScale(r, r);
+ _gameTopX = 0;
+ _gameTopY = (240.f - r * _gameHeight) / 2.f;
+ } else {
+ float r = 240.f / _gameHeight;
+ _gameTopTexture.setScale(r, r);
+ _gameTopY = 0;
+ _gameTopX = (400.f - r * _gameWidth) / 2.f;
+ }
+ if (ratio > 320.f / 240.f) {
+ float r = 320.f / _gameWidth;
+ _gameBottomTexture.setScale(r, r);
+ _gameBottomX = 0;
+ _gameBottomY = (240.f - r * _gameHeight) / 2.f;
+ } else {
+ float r = 240.f / _gameHeight;
+ _gameBottomTexture.setScale(r, r);
+ _gameBottomY = 0;
+ _gameBottomX = (320.f - r * _gameWidth) / 2.f;
+ }
+ }
+ _gameTopTexture.setPosition(_gameTopX, _gameTopY);
+ _gameBottomTexture.setPosition(_gameBottomX, _gameBottomY);
+ if (_overlayVisible)
+ _cursorTexture.setScale(1.f, 1.f);
+ else if (config.screen == kScreenTop)
+ _cursorTexture.setScale(_gameTopTexture.getScaleX(), _gameTopTexture.getScaleY());
+ else
+ _cursorTexture.setScale(_gameBottomTexture.getScaleX(), _gameBottomTexture.getScaleY());
+}
+
+Common::List<Graphics::PixelFormat> OSystem_3DS::getSupportedFormats() const {
+ Common::List<Graphics::PixelFormat> list;
+ list.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); // GPU_RGBA8
+ list.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); // GPU_RGB565
+// list.push_back(Graphics::PixelFormat(3, 0, 0, 0, 8, 0, 8, 16, 0)); // GPU_RGB8
+ list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); // RGB555 (needed for FMTOWNS?)
+ list.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)); // GPU_RGBA5551
+ list.push_back(Graphics::PixelFormat::createFormatCLUT8());
+ return list;
+}
+
+void OSystem_3DS::beginGFXTransaction() {
+ //
+}
+OSystem::TransactionError OSystem_3DS::endGFXTransaction() {
+ return OSystem::kTransactionSuccess;
+}
+
+void OSystem_3DS::setPalette(const byte *colors, uint start, uint num) {
+ assert(start + num <= 256);
+ memcpy(_palette + 3 * start, colors, 3 * num);
+
+ // Manually update all color that were changed
+ if (_gameScreen.format.bytesPerPixel == 1) {
+ flushGameScreen();
+ }
+}
+void OSystem_3DS::grabPalette(byte *colors, uint start, uint num) {
+ assert(start + num <= 256);
+ memcpy(colors, _palette + 3 * start, 3 * num);
+}
+
+void OSystem_3DS::copyRectToScreen(const void *buf, int pitch, int x,
+ int y, int w, int h) {
+ Common::Rect rect(x, y, x+w, y+h);
+ _gameScreen.copyRectToSurface(buf, pitch, x, y, w, h);
+ Graphics::Surface subSurface = _gameScreen.getSubArea(rect);
+
+ Graphics::Surface *convertedSubSurface = subSurface.convertTo(_pfGameTexture, _palette);
+ _gameTopTexture.copyRectToSurface(*convertedSubSurface, x, y, Common::Rect(w, h));
+
+ convertedSubSurface->free();
+ delete convertedSubSurface;
+ _gameTopTexture.markDirty();
+}
+
+void OSystem_3DS::flushGameScreen() {
+ Graphics::Surface *converted = _gameScreen.convertTo(_pfGameTexture, _palette);
+ _gameTopTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+ _gameTopTexture.markDirty();
+ converted->free();
+ delete converted;
+}
+
+Graphics::Surface *OSystem_3DS::lockScreen() {
+ return &_gameScreen;
+}
+void OSystem_3DS::unlockScreen() {
+ flushGameScreen();
+}
+
+void OSystem_3DS::updateScreen() {
+
+ if (sleeping || exiting)
+ return;
+
+// updateFocus();
+
+ C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
+ // Render top screen
+ C3D_FrameDrawOn(_renderTargetTop);
+ if (config.screen == kScreenTop || config.screen == kScreenBoth) {
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionTop);
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _gameTopTexture.getMatrix());
+ _gameTopTexture.render();
+ _gameTopTexture.render();
+ if (_overlayVisible && config.screen == kScreenTop) {
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _overlay.getMatrix());
+ _overlay.render();
+ }
+ if (_cursorVisible && config.showCursor && config.screen == kScreenTop) {
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _cursorTexture.getMatrix());
+ _cursorTexture.render();
+ }
+ }
+
+ // Render bottom screen
+ C3D_FrameDrawOn(_renderTargetBottom);
+ if (config.screen == kScreenBottom || config.screen == kScreenBoth) {
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _projectionLocation, &_projectionBottom);
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _gameBottomTexture.getMatrix());
+ _gameTopTexture.render();
+ _gameTopTexture.render();
+ if (_overlayVisible) {
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _overlay.getMatrix());
+ _overlay.render();
+ }
+ if (_cursorVisible && config.showCursor) {
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, _modelviewLocation, _cursorTexture.getMatrix());
+ _cursorTexture.render();
+ }
+ }
+ C3D_FrameEnd(0);
+}
+
+void OSystem_3DS::setShakePos(int shakeOffset) {
+ // TODO: implement this in overlay, top screen, and mouse too
+ _screenShakeOffset = shakeOffset;
+ _gameTopTexture.setPosition(_gameTopX, _gameTopY + _gameTopTexture.getScaleY() * shakeOffset);
+ _gameBottomTexture.setPosition(_gameBottomX, _gameBottomY + _gameBottomTexture.getScaleY() * shakeOffset);
+}
+
+void OSystem_3DS::setFocusRectangle(const Common::Rect &rect) {
+ debug("setfocus: %d %d %d %d", rect.left, rect.top, rect.width(), rect.height());
+ _focusRect = rect;
+ _focusDirty = true;
+ _focusClearTime = 0;
+}
+
+void OSystem_3DS::clearFocusRectangle() {
+ _focusClearTime = getMillis();
+}
+
+void OSystem_3DS::updateFocus() {
+
+ if (_focusClearTime && getMillis() - _focusClearTime > 5000) {
+ _focusClearTime = 0;
+ _focusDirty = true;
+ _focusRect = Common::Rect(_gameWidth, _gameHeight);
+ }
+
+ if (_focusDirty) {
+ float duration = 1.f / 20.f; // Focus animation in frame duration
+ float w = 400.f;
+ float h = 240.f;
+ float ratio = _focusRect.width() / _focusRect.height();
+ if (ratio > w/h) {
+ _focusTargetScaleX = w / _focusRect.width();
+ float newHeight = (float)_focusRect.width() / w/h;
+ _focusTargetScaleY = h / newHeight;
+ _focusTargetPosX = _focusTargetScaleX * _focusRect.left;
+ _focusTargetPosY = _focusTargetScaleY * ((float)_focusRect.top - (newHeight - _focusRect.height())/2.f);
+ } else {
+ _focusTargetScaleY = h / _focusRect.height();
+ float newWidth = (float)_focusRect.height() * w/h;
+ _focusTargetScaleX = w / newWidth;
+ _focusTargetPosY = _focusTargetScaleY * _focusRect.top;
+ _focusTargetPosX = _focusTargetScaleX * ((float)_focusRect.left - (newWidth - _focusRect.width())/2.f);
+ }
+ if (_focusTargetPosX < 0 && _focusTargetScaleY != 240.f / _gameHeight)
+ _focusTargetPosX = 0;
+ if (_focusTargetPosY < 0 && _focusTargetScaleX != 400.f / _gameWidth)
+ _focusTargetPosY = 0;
+ _focusStepPosX = duration * (_focusTargetPosX - _focusPosX);
+ _focusStepPosY = duration * (_focusTargetPosY - _focusPosY);
+ _focusStepScaleX = duration * (_focusTargetScaleX - _focusScaleX);
+ _focusStepScaleY = duration * (_focusTargetScaleY - _focusScaleY);
+ }
+
+ if (_focusDirty || _focusPosX != _focusTargetPosX || _focusPosY != _focusTargetPosY ||
+ _focusScaleX != _focusTargetScaleX || _focusScaleY != _focusTargetScaleY) {
+ _focusDirty = false;
+
+ if ((_focusStepPosX > 0 && _focusPosX > _focusTargetPosX) || (_focusStepPosX < 0 && _focusPosX < _focusTargetPosX))
+ _focusPosX = _focusTargetPosX;
+ else if (_focusPosX != _focusTargetPosX)
+ _focusPosX += _focusStepPosX;
+
+ if ((_focusStepPosY > 0 && _focusPosY > _focusTargetPosY) || (_focusStepPosY < 0 && _focusPosY < _focusTargetPosY))
+ _focusPosY = _focusTargetPosY;
+ else if (_focusPosY != _focusTargetPosY)
+ _focusPosY += _focusStepPosY;
+
+ if ((_focusStepScaleX > 0 && _focusScaleX > _focusTargetScaleX) || (_focusStepScaleX < 0 && _focusScaleX < _focusTargetScaleX))
+ _focusScaleX = _focusTargetScaleX;
+ else if (_focusScaleX != _focusTargetScaleX)
+ _focusScaleX += _focusStepScaleX;
+
+ if ((_focusStepScaleY > 0 && _focusScaleY > _focusTargetScaleY) || (_focusStepScaleY < 0 && _focusScaleY < _focusTargetScaleY))
+ _focusScaleY = _focusTargetScaleY;
+ else if (_focusScaleY != _focusTargetScaleY)
+ _focusScaleY += _focusStepScaleY;
+
+ Mtx_Identity(&_focusMatrix);
+ Mtx_Translate(&_focusMatrix, -_focusPosX, -_focusPosY, 0);
+ Mtx_Scale(&_focusMatrix, _focusScaleX, _focusScaleY, 1.f);
+ }
+}
+
+void OSystem_3DS::showOverlay() {
+ _overlayVisible = true;
+ updateSize();
+ updateScreen();
+}
+
+void OSystem_3DS::hideOverlay() {
+ _overlayVisible = false;
+ updateSize();
+ updateScreen();
+}
+
+Graphics::PixelFormat OSystem_3DS::getOverlayFormat() const {
+ return _pfGameTexture;
+}
+
+void OSystem_3DS::clearOverlay() {
+ _overlay.clear();
+}
+
+void OSystem_3DS::grabOverlay(void *buf, int pitch) {
+ for (int y = 0; y < getOverlayHeight(); ++y) {
+ memcpy(buf, _overlay.getBasePtr(0, y), pitch);
+ }
+}
+
+void OSystem_3DS::copyRectToOverlay(const void *buf, int pitch, int x,
+ int y, int w, int h) {
+ _overlay.copyRectToSurface(buf, pitch, x, y, w, h);
+ _overlay.markDirty();
+}
+
+int16 OSystem_3DS::getOverlayHeight() {
+ return 240;
+}
+
+int16 OSystem_3DS::getOverlayWidth() {
+ return 320;
+}
+
+bool OSystem_3DS::showMouse(bool visible) {
+ _cursorVisible = visible;
+ flushCursor();
+ return !visible;
+}
+
+void OSystem_3DS::warpMouse(int x, int y) {
+ _cursorX = x;
+ _cursorY = y;
+ warning("x:%d y:%d", x, y);
+ // TODO: adjust for _cursorScalable ?
+ int offsetx = 0;
+ int offsety = 0;
+ x -= _cursorHotspotX;
+ y -= _cursorHotspotY;
+ if (!_overlayVisible) {
+ offsetx += config.screen == kScreenTop ? _gameTopX : _gameBottomX;
+ offsety += config.screen == kScreenTop ? _gameTopY : _gameBottomY;
+ }
+ float scalex = config.screen == kScreenTop ? (float)_gameTopTexture.actualWidth / _gameWidth : 1.f;
+ float scaley = config.screen == kScreenTop ? (float)_gameTopTexture.actualHeight / _gameHeight : 1.f;
+ _cursorTexture.setPosition(scalex * x + offsetx,
+ scaley * y + offsety);
+}
+
+void OSystem_3DS::setCursorDelta(float deltaX, float deltaY) {
+ _cursorDeltaX = deltaX;
+ _cursorDeltaY = deltaY;
+}
+
+void OSystem_3DS::setMouseCursor(const void *buf, uint w, uint h,
+ int hotspotX, int hotspotY,
+ uint32 keycolor, bool dontScale,
+ const Graphics::PixelFormat *format) {
+ _cursorScalable = !dontScale;
+ _cursorHotspotX = hotspotX;
+ _cursorHotspotY = hotspotY;
+ _cursorKeyColor = keycolor;
+ _pfCursor = !format ? Graphics::PixelFormat::createFormatCLUT8() : *format;
+
+ if (w != _cursor.w || h != _cursor.h || _cursor.format != _pfCursor) {
+ _cursor.create(w, h, _pfCursor);
+ _cursorTexture.create(w, h, _pfGameTexture);
+ }
+
+ _cursor.copyRectToSurface(buf, w, 0, 0, w, h);
+ flushCursor();
+
+ warpMouse(_cursorX, _cursorY);
+}
+
+void OSystem_3DS::setCursorPalette(const byte *colors, uint start, uint num) {
+ assert(start + num <= 256);
+ memcpy(_cursorPalette + 3 * start, colors, 3 * num);
+ _cursorPaletteEnabled = true;
+ flushCursor();
+}
+
+void OSystem_3DS::flushCursor() {
+ if (_cursor.getPixels()) {
+ Graphics::Surface *converted = _cursor.convertTo(_pfGameTexture, _cursorPaletteEnabled ? _cursorPalette : _palette);
+ _cursorTexture.copyRectToSurface(*converted, 0, 0, Common::Rect(converted->w, converted->h));
+ _cursorTexture.markDirty();
+ converted->free();
+ delete converted;
+
+ if (_pfCursor.bytesPerPixel == 1) {
+ uint* dest = (uint*) _cursorTexture.getPixels();
+ byte* src = (byte*) _cursor.getPixels();
+ for (int y = 0; y < _cursor.h; ++y) {
+ for (int x = 0; x < _cursor.w; ++x) {
+ if (*src++ == _cursorKeyColor)
+ *dest++ = 0;
+ else
+ dest++;
+ }
+ dest += _cursorTexture.w - _cursorTexture.actualWidth;
+ }
+ }
+ }
+}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem.cpp b/backends/platform/3ds/osystem.cpp
new file mode 100644
index 0000000000..f6278eb16b
--- /dev/null
+++ b/backends/platform/3ds/osystem.cpp
@@ -0,0 +1,193 @@
+/* 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.
+ *
+ */
+
+#define FORBIDDEN_SYMBOL_EXCEPTION_printf
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
+#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
+
+#include "osystem.h"
+
+#include "backends/saves/default/default-saves.h"
+#include "backends/timer/default/default-timer.h"
+#include "backends/events/default/default-events.h"
+#include "audio/mixer_intern.h"
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/str.h"
+#include "config.h"
+
+#include "backends/fs/posix/posix-fs-factory.h"
+#include "backends/fs/posix/posix-fs.h"
+#include <unistd.h>
+#include <time.h>
+
+namespace _3DS {
+
+OSystem_3DS::OSystem_3DS():
+ _focusDirty(true),
+ _focusRect(Common::Rect(1, 1)),
+ _focusPosX(0),
+ _focusPosY(0),
+ _focusTargetPosX(0),
+ _focusTargetPosY(0),
+ _focusStepPosX(0),
+ _focusStepPosY(0),
+ _focusScaleX(1.f),
+ _focusScaleY(1.f),
+ _focusTargetScaleX(1.f),
+ _focusTargetScaleY(1.f),
+ _focusStepScaleX(0.f),
+ _focusStepScaleY(0.f),
+ _focusClearTime(0),
+ _cursorPaletteEnabled(false),
+ _cursorVisible(false),
+ _cursorScalable(false),
+ _cursorX(0),
+ _cursorY(0),
+ _cursorHotspotX(0),
+ _cursorHotspotY(0),
+ _gameTopX(0),
+ _gameTopY(0),
+ _gameBottomX(0),
+ _gameBottomY(0),
+ _gameWidth(320),
+ _gameHeight(240),
+ _overlayVisible(false),
+ exiting(false),
+ sleeping(false)
+{
+ chdir("sdmc:/");
+ _fsFactory = new POSIXFilesystemFactory();
+ Posix::assureDirectoryExists("/3ds/scummvm/saves/");
+}
+
+OSystem_3DS::~OSystem_3DS() {
+ exiting = true;
+ destroyEvents();
+ destroyAudio();
+ destroyGraphics();
+
+ delete _timerManager;
+ _timerManager = 0;
+}
+
+void OSystem_3DS::quit() {
+ printf("OSystem_3DS::quit()\n");
+}
+
+void OSystem_3DS::initBackend() {
+ loadConfig();
+ ConfMan.registerDefault("fullscreen", true);
+ ConfMan.registerDefault("aspect_ratio", true);
+ if (!ConfMan.hasKey("vkeybd_pack_name"))
+ ConfMan.set("vkeybd_pack_name", "vkeybd_small");
+ if (!ConfMan.hasKey("vkeybdpath"))
+ ConfMan.set("vkeybdpath", "/3ds/scummvm/kb");
+ if (!ConfMan.hasKey("themepath"))
+ ConfMan.set("themepath", "/3ds/scummvm");
+ if (!ConfMan.hasKey("gui_theme"))
+ ConfMan.set("gui_theme", "builtin");
+
+ _timerManager = new DefaultTimerManager();
+ _savefileManager = new DefaultSaveFileManager("/3ds/scummvm/saves/");
+
+ initGraphics();
+ initAudio();
+ initEvents();
+ EventsBaseBackend::initBackend();
+}
+
+void OSystem_3DS::updateConfig() {
+ if (_gameScreen.getPixels()) {
+ updateSize();
+ warpMouse(_cursorX, _cursorY);
+ }
+}
+
+Common::String OSystem_3DS::getDefaultConfigFileName() {
+ return "/3ds/scummvm/scummvm.ini";
+}
+
+uint32 OSystem_3DS::getMillis(bool skipRecord) {
+ return svcGetSystemTick() / TICKS_PER_MSEC;
+}
+
+void OSystem_3DS::delayMillis(uint msecs) {
+ svcSleepThread(msecs * 1000000);
+}
+
+void OSystem_3DS::getTimeAndDate(TimeDate& td) const {
+ time_t curTime = time(0);
+ struct tm t = *localtime(&curTime);
+ td.tm_sec = t.tm_sec;
+ td.tm_min = t.tm_min;
+ td.tm_hour = t.tm_hour;
+ td.tm_mday = t.tm_mday;
+ td.tm_mon = t.tm_mon;
+ td.tm_year = t.tm_year;
+ td.tm_wday = t.tm_wday;
+}
+
+OSystem::MutexRef OSystem_3DS::createMutex() {
+ RecursiveLock *mutex = new RecursiveLock();
+ RecursiveLock_Init(mutex);
+ return (OSystem::MutexRef) mutex;
+}
+void OSystem_3DS::lockMutex(MutexRef mutex) {
+ RecursiveLock_Lock((RecursiveLock*)mutex);
+}
+void OSystem_3DS::unlockMutex(MutexRef mutex) {
+ RecursiveLock_Unlock((RecursiveLock*)mutex);
+}
+void OSystem_3DS::deleteMutex(MutexRef mutex) {
+ delete (RecursiveLock*)mutex;
+}
+
+Common::String OSystem_3DS::getSystemLanguage() const {
+ u8 langcode;
+ CFGU_GetSystemLanguage(&langcode);
+ switch (langcode) {
+ case CFG_LANGUAGE_JP: return "ja_JP";
+ case CFG_LANGUAGE_EN: return "en_US";
+ case CFG_LANGUAGE_FR: return "fr_FR";
+ case CFG_LANGUAGE_DE: return "de_DE";
+ case CFG_LANGUAGE_IT: return "it_IT";
+ case CFG_LANGUAGE_ES: return "es_ES";
+ case CFG_LANGUAGE_ZH: return "zh_CN";
+ case CFG_LANGUAGE_KO: return "ko_KR";
+ case CFG_LANGUAGE_NL: return "nl_NL";
+ case CFG_LANGUAGE_PT: return "pt_BR";
+ case CFG_LANGUAGE_RU: return "ru_RU";
+ case CFG_LANGUAGE_TW: return "zh_HK";
+ default: return "en_US";
+ }
+}
+
+void OSystem_3DS::fatalError() {
+ printf("FatalError!\n");
+}
+
+void OSystem_3DS::logMessage(LogMessageType::Type type, const char *message) {
+ printf("3DS log: %s\n", message);
+}
+
+} // namespace _3DS
diff --git a/backends/platform/3ds/osystem.h b/backends/platform/3ds/osystem.h
new file mode 100644
index 0000000000..478085acba
--- /dev/null
+++ b/backends/platform/3ds/osystem.h
@@ -0,0 +1,221 @@
+/* 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.
+ *
+ */
+
+#ifndef PLATFORM_3DS_H
+#define PLATFORM_3DS_H
+
+#include <citro3d.h>
+#include "backends/mutex/mutex.h"
+#include "backends/base-backend.h"
+#include "graphics/palette.h"
+#include "base/main.h"
+#include "audio/mixer_intern.h"
+#include "backends/graphics/graphics.h"
+#include "backends/platform/3ds/sprite.h"
+#include "common/rect.h"
+#include "common/queue.h"
+
+#define TICKS_PER_MSEC 268123
+
+namespace _3DS {
+
+enum {
+ GFX_LINEAR = 0,
+ GFX_NEAREST = 1
+};
+
+enum InputMode {
+ MODE_HOVER,
+ MODE_DRAG,
+};
+
+static const OSystem::GraphicsMode s_graphicsModes[] = {
+ {"default", "Default Test", GFX_LINEAR},
+ { 0, 0, 0 }
+};
+
+class OSystem_3DS : public EventsBaseBackend, public PaletteManager {
+public:
+ OSystem_3DS();
+ virtual ~OSystem_3DS();
+
+ volatile bool exiting;
+ volatile bool sleeping;
+
+ virtual void initBackend();
+
+ virtual bool hasFeature(OSystem::Feature f);
+ virtual void setFeatureState(OSystem::Feature f, bool enable);
+ virtual bool getFeatureState(OSystem::Feature f);
+
+ virtual bool pollEvent(Common::Event &event);
+
+ virtual uint32 getMillis(bool skipRecord = false);
+ virtual void delayMillis(uint msecs);
+ virtual void getTimeAndDate(TimeDate &t) const;
+
+ virtual MutexRef createMutex();
+ virtual void lockMutex(MutexRef mutex);
+ virtual void unlockMutex(MutexRef mutex);
+ virtual void deleteMutex(MutexRef mutex);
+
+ virtual void logMessage(LogMessageType::Type type, const char *message);
+
+ virtual Audio::Mixer *getMixer();
+ virtual PaletteManager *getPaletteManager() { return this; }
+ virtual Common::String getSystemLanguage() const;
+ virtual void fatalError();
+ virtual void quit();
+
+ virtual Common::String getDefaultConfigFileName();
+
+ // Graphics
+ virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
+ int getDefaultGraphicsMode() const;
+ bool setGraphicsMode(int mode);
+ void resetGraphicsScale();
+ int getGraphicsMode() const;
+ inline Graphics::PixelFormat getScreenFormat() const { return _pfGame; }
+ virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
+ void initSize(uint width, uint height,
+ const Graphics::PixelFormat *format = NULL);
+ virtual int getScreenChangeID() const { return 0; };
+
+ void beginGFXTransaction();
+ OSystem::TransactionError endGFXTransaction();
+ int16 getHeight(){ return _gameHeight; }
+ int16 getWidth(){ return _gameWidth; }
+ void setPalette(const byte *colors, uint start, uint num);
+ void grabPalette(byte *colors, uint start, uint num);
+ void copyRectToScreen(const void *buf, int pitch, int x, int y, int w,
+ int h);
+ Graphics::Surface *lockScreen();
+ void unlockScreen();
+ void updateScreen();
+ void setShakePos(int shakeOffset);
+ void setFocusRectangle(const Common::Rect &rect);
+ void clearFocusRectangle();
+ void showOverlay();
+ void hideOverlay();
+ Graphics::PixelFormat getOverlayFormat() const;
+ void clearOverlay();
+ void grabOverlay(void *buf, int pitch);
+ void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w,
+ int h);
+ virtual int16 getOverlayHeight();
+ virtual int16 getOverlayWidth();
+ virtual void displayMessageOnOSD(const char *msg);
+
+ bool showMouse(bool visible);
+ void warpMouse(int x, int y);
+ void setMouseCursor(const void *buf, uint w, uint h, int hotspotX,
+ int hotspotY, uint32 keycolor, bool dontScale = false,
+ const Graphics::PixelFormat *format = NULL);
+ void setCursorPalette(const byte *colors, uint start, uint num);
+
+ // Transform point from touchscreen coords into gamescreen coords
+ void transformPoint(touchPosition &point);
+
+ void setCursorDelta(float deltaX, float deltaY);
+
+ void updateFocus();
+ void updateConfig();
+ void updateSize();
+
+private:
+ void initGraphics();
+ void destroyGraphics();
+ void initAudio();
+ void destroyAudio();
+ void initEvents();
+ void destroyEvents();
+
+ void flushGameScreen();
+ void flushCursor();
+
+protected:
+ Audio::MixerImpl *_mixer;
+
+private:
+ u16 _gameWidth, _gameHeight;
+ u16 _gameTopX, _gameTopY;
+ u16 _gameBottomX, _gameBottomY;
+
+ // Audio
+ Thread audioThread;
+
+ // Graphics
+ Graphics::PixelFormat _pfGame;
+ Graphics::PixelFormat _pfGameTexture;
+ Graphics::PixelFormat _pfCursor;
+ byte _palette[3 * 256];
+ byte _cursorPalette[3 * 256];
+
+ Graphics::Surface _gameScreen;
+ Sprite _gameTopTexture;
+ Sprite _gameBottomTexture;
+ Sprite _overlay;
+
+ int _screenShakeOffset;
+ bool _overlayVisible;
+
+ DVLB_s *_dvlb;
+ shaderProgram_s _program;
+ int _projectionLocation;
+ int _modelviewLocation;
+ C3D_Mtx _projectionTop;
+ C3D_Mtx _projectionBottom;
+ C3D_RenderTarget* _renderTargetTop;
+ C3D_RenderTarget* _renderTargetBottom;
+
+ // Focus
+ Common::Rect _focusRect;
+ bool _focusDirty;
+ C3D_Mtx _focusMatrix;
+ int _focusPosX, _focusPosY;
+ int _focusTargetPosX, _focusTargetPosY;
+ float _focusStepPosX, _focusStepPosY;
+ float _focusScaleX, _focusScaleY;
+ float _focusTargetScaleX, _focusTargetScaleY;
+ float _focusStepScaleX, _focusStepScaleY;
+ uint32 _focusClearTime;
+
+ // Events
+ Thread _eventThread;
+ Thread _timerThread;
+ Common::Queue<Common::Event> _eventQueue;
+
+ // Cursor
+ Graphics::Surface _cursor;
+ Sprite _cursorTexture;
+ bool _cursorPaletteEnabled;
+ bool _cursorVisible;
+ bool _cursorScalable;
+ float _cursorX, _cursorY;
+ float _cursorDeltaX, _cursorDeltaY;
+ int _cursorHotspotX, _cursorHotspotY;
+ uint32 _cursorKeyColor;
+};
+
+} // namespace _3DS
+
+#endif
diff --git a/backends/platform/3ds/shader.v.pica b/backends/platform/3ds/shader.v.pica
new file mode 100644
index 0000000000..2d18985622
--- /dev/null
+++ b/backends/platform/3ds/shader.v.pica
@@ -0,0 +1,59 @@
+;* 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.
+;*
+
+; Uniforms
+.fvec projection[4], modelView[4]
+
+; Constants
+.constf myconst(0.0, 1.0, -1.0, 0.1)
+.alias zeros myconst.xxxx ; Vector full of zeros
+.alias ones myconst.yyyy ; Vector full of ones
+
+; Outputs
+.out outpos position
+.out outtex texcoord0
+
+; Inputs (defined as aliases for convenience)
+.alias inpos v0
+.alias intex v1
+
+.proc main
+ ; Force the w component of inpos to be 1.0
+ mov r0.xyz, inpos
+ mov r0.w, ones
+
+ ; r1 = modelView * inpos
+ dp4 r1.x, modelView[0], r0
+ dp4 r1.y, modelView[1], r0
+ dp4 r1.z, modelView[2], r0
+ dp4 r1.w, modelView[3], r0
+
+ ; outpos = projection * r1
+ dp4 outpos.x, projection[0], r1
+ dp4 outpos.y, projection[1], r1
+ dp4 outpos.z, projection[2], r1
+ dp4 outpos.w, projection[3], r1
+
+ mov outtex, intex
+
+ end
+.end
+
diff --git a/backends/platform/3ds/sprite.cpp b/backends/platform/3ds/sprite.cpp
new file mode 100644
index 0000000000..f97c611473
--- /dev/null
+++ b/backends/platform/3ds/sprite.cpp
@@ -0,0 +1,144 @@
+/* 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.
+ *
+ */
+
+#include "backends/platform/3ds/sprite.h"
+#include "common/util.h"
+#include <3ds.h>
+
+static uint nextHigher2(uint v) {
+ if (v == 0)
+ return 1;
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return ++v;
+}
+
+Sprite::Sprite()
+ : dirtyPixels(true)
+ , dirtyMatrix(true)
+ , actualWidth(0)
+ , actualHeight(0)
+ , posX(0)
+ , posY(0)
+ , scaleX(1.f)
+ , scaleY(1.f)
+{
+ Mtx_Identity(&modelview);
+
+ vertices = (vertex *)linearAlloc(sizeof(vertex) * 4);
+}
+
+Sprite::~Sprite() {
+ //
+}
+
+void Sprite::create(uint16 width, uint16 height, const Graphics::PixelFormat &f) {
+ free();
+
+ actualWidth = width;
+ actualHeight = height;
+ format = f;
+ w = MAX(nextHigher2(width), 64u);
+ h = MAX(nextHigher2(height), 64u);
+ pitch = w * format.bytesPerPixel;
+ dirtyPixels = true;
+
+ if (width && height) {
+ pixels = linearAlloc(h * pitch);
+ C3D_TexInit(&texture, w, h, GPU_RGBA8);
+ C3D_TexSetFilter(&texture, GPU_LINEAR, GPU_LINEAR);
+ assert(pixels && texture.data);
+ clear();
+ }
+
+ float x = 0.f, y = 0.f;
+ float u = (float)width/w;
+ float v = (float)height/h;
+ vertex tmp[4] = {
+ {{x, y, 0.5f}, {0, 0}},
+ {{x+width, y, 0.5f}, {u, 0}},
+ {{x, y+height, 0.5f}, {0, v}},
+ {{x+width, y+height, 0.5f}, {u, v}},
+ };
+ memcpy(vertices, tmp, sizeof(vertex) * 4);
+}
+
+
+void Sprite::free() {
+ linearFree(vertices);
+ linearFree(pixels);
+ C3D_TexDelete(&texture);
+ pixels = 0;
+ w = h = pitch = 0;
+ actualWidth = actualHeight = 0;
+ format = Graphics::PixelFormat();
+}
+
+void Sprite::convertToInPlace(const Graphics::PixelFormat &dstFormat, const byte *palette) {
+ //
+}
+
+void Sprite::render() {
+ if (dirtyPixels) {
+ dirtyPixels = false;
+ GSPGPU_FlushDataCache(pixels, w * h * format.bytesPerPixel);
+ C3D_SafeDisplayTransfer((u32*)pixels, GX_BUFFER_DIM(w, h), (u32*)texture.data, GX_BUFFER_DIM(w, h), TEXTURE_TRANSFER_FLAGS);
+ gspWaitForPPF();
+ }
+ C3D_TexBind(0, &texture);
+
+ C3D_BufInfo *bufInfo = C3D_GetBufInfo();
+ BufInfo_Init(bufInfo);
+ BufInfo_Add(bufInfo, vertices, sizeof(vertex), 2, 0x10);
+ C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4);
+}
+
+void Sprite::clear(uint32 color) {
+ dirtyPixels = true;
+ memset(pixels, color, w * h * format.bytesPerPixel);
+}
+
+void Sprite::setScale (float x, float y) {
+ scaleX = x;
+ scaleY = y;
+ dirtyMatrix = true;
+}
+
+void Sprite::setPosition(int x, int y) {
+ posX = x;
+ posY = y;
+ dirtyMatrix = true;
+}
+
+C3D_Mtx* Sprite::getMatrix() {
+ if (dirtyMatrix) {
+ dirtyMatrix = false;
+ Mtx_Identity(&modelview);
+ Mtx_Scale(&modelview, scaleX, scaleY, 1.f);
+ Mtx_Translate(&modelview, posX, posY, 0);
+ }
+ return &modelview;
+}
diff --git a/backends/platform/3ds/sprite.h b/backends/platform/3ds/sprite.h
new file mode 100644
index 0000000000..6d88ae4ce1
--- /dev/null
+++ b/backends/platform/3ds/sprite.h
@@ -0,0 +1,71 @@
+/* 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.
+ *
+ */
+
+#ifndef GRAPHICS_SPRITE_3DS_H
+#define GRAPHICS_SPRITE_3DS_H
+
+#include <citro3d.h>
+#include "graphics/surface.h"
+
+#define TEXTURE_TRANSFER_FLAGS \
+ (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | \
+ GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
+ GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+
+typedef struct {
+ float position[3];
+ float texcoord[2];
+} vertex;
+
+class Sprite : public Graphics::Surface {
+public:
+ Sprite();
+ ~Sprite();
+ void create(uint16 width, uint16 height, const Graphics::PixelFormat &format);
+ void free();
+ void convertToInPlace(const Graphics::PixelFormat &dstFormat, const byte *palette = 0);
+ void render();
+ void clear(uint32 color = 0);
+ void markDirty(){ dirtyPixels = true; }
+
+ void setPosition(int x, int y);
+ void setScale(float x, float y);
+ float getScaleX(){ return scaleX; }
+ float getScaleY(){ return scaleY; }
+ C3D_Mtx* getMatrix();
+
+ uint16 actualWidth;
+ uint16 actualHeight;
+
+private:
+ bool dirtyPixels;
+ bool dirtyMatrix;
+ C3D_Mtx modelview;
+ C3D_Tex texture;
+ vertex* vertices;
+ int posX;
+ int posY;
+ float scaleX;
+ float scaleY;
+};
+
+#endif
diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index e11ad0724e..4a29526941 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -1,9 +1,9 @@
# Android specific build targets
# These must be incremented for each market upload
-ANDROID_VERSIONCODE = 6
+ANDROID_VERSIONCODE = 16
-ANDROID_TARGET_VERSION = 14
+ANDROID_TARGET_VERSION = 23
NDK_BUILD = $(ANDROID_NDK)/ndk-build APP_ABI=$(ABI)
SDK_ANDROID = $(ANDROID_SDK)/tools/android
@@ -20,6 +20,7 @@ RESOURCES = \
$(PATH_BUILD_RES)/layout/main.xml \
$(PATH_BUILD_RES)/drawable/scummvm.png \
$(PATH_BUILD_RES)/drawable/scummvm_big.png \
+ $(PATH_BUILD_RES)/drawable-xhdpi/leanback_icon.png \
$(PATH_BUILD_RES)/drawable-xhdpi/ouya_icon.png
DIST_ANDROID_MK = $(PATH_DIST)/jni/Android.mk
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
index 8039981a92..b146945a01 100644
--- a/backends/platform/android/events.cpp
+++ b/backends/platform/android/events.cpp
@@ -101,7 +101,9 @@ enum {
JKEYCODE_MEDIA_NEXT = 87,
JKEYCODE_MEDIA_PREVIOUS = 88,
JKEYCODE_MEDIA_REWIND = 89,
- JKEYCODE_MEDIA_FAST_FORWARD = 90
+ JKEYCODE_MEDIA_FAST_FORWARD = 90,
+ JKEYCODE_MEDIA_PLAY = 126,
+ JKEYCODE_MEDIA_PAUSE = 127
};
// five-way navigation control
@@ -380,6 +382,19 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
return;
+ case JKEYCODE_MEDIA_PAUSE:
+ case JKEYCODE_MEDIA_PLAY:
+ case JKEYCODE_MEDIA_PLAY_PAUSE:
+ if (arg1 == JACTION_DOWN) {
+ e.type = Common::EVENT_MAINMENU;
+
+ lockMutex(_event_queue_lock);
+ _event_queue.push(e);
+ unlockMutex(_event_queue_lock);
+ }
+
+ return;
+
case JKEYCODE_CAMERA:
case JKEYCODE_SEARCH:
if (arg1 == JACTION_DOWN)
@@ -888,6 +903,10 @@ void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
e.kbd.ascii = Common::ASCII_ESCAPE;
break;
+ case JKEYCODE_BUTTON_Y:
+ e.type = Common::EVENT_MAINMENU;
+ break;
+
default:
LOGW("unmapped gamepad key: %d", arg2);
return;
diff --git a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
index 32c65d3395..e81000d8b1 100644
--- a/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
+++ b/backends/platform/android/org/scummvm/scummvm/ScummVMEvents.java
@@ -119,6 +119,8 @@ public class ScummVMEvents implements
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_CAMERA:
case KeyEvent.KEYCODE_SEARCH:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
break;
default:
diff --git a/backends/platform/androidsdl/androidsdl-main.cpp b/backends/platform/androidsdl/androidsdl-main.cpp
new file mode 100644
index 0000000000..26a73579c0
--- /dev/null
+++ b/backends/platform/androidsdl/androidsdl-main.cpp
@@ -0,0 +1,42 @@
+/* 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.
+ *
+ */
+
+#include "backends/platform/androidsdl/androidsdl-sdl.h"
+#include "base/main.h"
+
+int main(int argc, char *argv[]) {
+
+ // Create our OSystem instance
+ g_system = new OSystem_ANDROIDSDL();
+ assert(g_system);
+
+ // Pre initialize the backend
+ ((OSystem_POSIX *)g_system)->init();
+
+ // Invoke the actual ScummVM main entry point:
+ int res = scummvm_main(argc, argv);
+
+ // Free OSystem
+ delete (OSystem_ANDROIDSDL *)g_system;
+
+ return res;
+}
diff --git a/backends/platform/androidsdl/androidsdl-sdl.cpp b/backends/platform/androidsdl/androidsdl-sdl.cpp
new file mode 100644
index 0000000000..5e0eaa0408
--- /dev/null
+++ b/backends/platform/androidsdl/androidsdl-sdl.cpp
@@ -0,0 +1,37 @@
+/* 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.
+ *
+ */
+
+#include "backends/platform/androidsdl/androidsdl-sdl.h"
+#include "backends/events/androidsdl/androidsdl-events.h"
+#include "backends/graphics/androidsdl/androidsdl-graphics.h"
+
+void OSystem_ANDROIDSDL::initBackend() {
+ // Create the backend custom managers
+ if (_eventSource == 0)
+ _eventSource = new AndroidSdlEventSource();
+
+ if (_graphicsManager == 0)
+ _graphicsManager = new AndroidSdlGraphicsManager(_eventSource, _window);
+
+ // Call parent implementation of this method
+ OSystem_POSIX::initBackend();
+}
diff --git a/backends/platform/androidsdl/androidsdl-sdl.h b/backends/platform/androidsdl/androidsdl-sdl.h
new file mode 100644
index 0000000000..6ebe5022eb
--- /dev/null
+++ b/backends/platform/androidsdl/androidsdl-sdl.h
@@ -0,0 +1,38 @@
+/* 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.
+ *
+ */
+
+#ifndef PLATFORM_SDL_ANDROIDSDL_H
+#define PLATFORM_SDL_ANDROIDSDL_H
+
+#include "backends/platform/sdl/posix/posix.h"
+
+class OSystem_ANDROIDSDL : public OSystem_POSIX {
+public:
+ virtual void initBackend();
+
+#ifdef ENABLE_KEYMAPPER
+ // FIXME: This just calls parent methods, is it needed?
+ virtual Common::HardwareInputSet *getHardwareInputSet();
+#endif
+};
+
+#endif
diff --git a/backends/platform/androidsdl/androidsdl.mk b/backends/platform/androidsdl/androidsdl.mk
new file mode 100644
index 0000000000..1defb81b97
--- /dev/null
+++ b/backends/platform/androidsdl/androidsdl.mk
@@ -0,0 +1,11 @@
+# Special target to create an AndroidSDL snapshot
+androidsdl:
+ $(MKDIR) release
+ $(INSTALL) -c -m 644 $(DIST_FILES_THEMES) $(DIST_FILES_ENGINEDATA) release
+ $(INSTALL) -c -m 644 $(DIST_FILES_DOCS) release
+ $(CP) $(srcdir)/backends/vkeybd/packs/vkeybd_default.zip release
+ zip -j scummvm190-git-appdata.zip release/*
+ split -d -b 1000000 scummvm190-git-appdata.zip scummvm190-git-appdata.zip0
+ $(RM) -r scummvm190-git-appdata.zip
+
+.PHONY: androidsdl
diff --git a/backends/platform/androidsdl/module.mk b/backends/platform/androidsdl/module.mk
new file mode 100644
index 0000000000..df927163b8
--- /dev/null
+++ b/backends/platform/androidsdl/module.mk
@@ -0,0 +1,13 @@
+MODULE := backends/platform/androidsdl
+
+MODULE_OBJS := \
+ androidsdl-main.o \
+ androidsdl-sdl.o
+
+# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
+MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
+OBJS := $(MODULE_OBJS) $(OBJS)
+MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))
+
+# Hack to ensure the SDL backend is built so we can use OSystem_SDL.
+-include $(srcdir)/backends/platform/sdl/module.mk
diff --git a/backends/platform/dc/dc.h b/backends/platform/dc/dc.h
index d8ab549c3a..6cd938ec9c 100644
--- a/backends/platform/dc/dc.h
+++ b/backends/platform/dc/dc.h
@@ -57,21 +57,16 @@ class DCHardware {
};
class DCCDManager : public DefaultAudioCDManager {
- // Initialize the specified CD drive for audio playback.
- bool openCD(int drive);
-
- // Poll cdrom status
- // Returns true if cd audio is playing
- bool pollCD();
-
- // Play cdrom audio track
- void playCD(int track, int num_loops, int start_frame, int duration);
+public:
+ // Poll cdrom status
+ // Returns true if cd audio is playing
+ bool isPlaying() const;
- // Stop cdrom audio track
- void stopCD();
+ // Play cdrom audio track
+ bool play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate = false);
- // Update cdrom audio status
- void updateCD();
+ // Stop cdrom audio track
+ void stop();
};
class OSystem_Dreamcast : private DCHardware, public EventsBaseBackend, public PaletteManager, public FilesystemFactory
diff --git a/backends/platform/dc/dcmain.cpp b/backends/platform/dc/dcmain.cpp
index eede796991..c84aef9c47 100644
--- a/backends/platform/dc/dcmain.cpp
+++ b/backends/platform/dc/dcmain.cpp
@@ -90,43 +90,53 @@ static bool find_track(int track, int &first_sec, int &last_sec)
return false;
}
-void DCCDManager::playCD(int track, int num_loops, int start_frame, int duration)
-{
- int first_sec, last_sec;
+bool DCCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate) {
+ DefaultAudioCDManager::play(track, numLoops, startFrame, duration, onlyEmulate);
+
+ // If we're playing now return here
+ if (isPlaying()) {
+ return true;
+ }
+
+ // If we should only play emulated tracks stop here.
+ if (onlyEmulate) {
+ return false;
+ }
+
+ int firstSec, lastSec;
#if 1
- if (num_loops)
- --num_loops;
+ if (numLoops)
+ --numLoops;
#endif
- if (num_loops>14) num_loops=14;
- else if (num_loops<0) num_loops=15; // infinity
- if (!find_track(track, first_sec, last_sec))
- return;
- if (duration)
- last_sec = first_sec + start_frame + duration;
- first_sec += start_frame;
- play_cdda_sectors(first_sec, last_sec, num_loops);
-}
-void DCCDManager::stopCD()
-{
- stop_cdda();
-}
+ if (numLoops > 14)
+ numLoops = 14;
+ else if (numLoops < 0)
+ numLoops = 15; // infinity
-bool DCCDManager::pollCD()
-{
- extern int getCdState();
- return getCdState() == 3;
+ if (!find_track(track, firstSec, lastSec))
+ return false;
+
+ if (duration)
+ lastSec = firstSec + startFrame + duration;
+
+ firstSec += startFrame;
+ play_cdda_sectors(firstSec, lastSec, numLoops);
+
+ return true;
}
-void DCCDManager::updateCD()
-{
- // Dummy. The CD drive takes care of itself.
+void DCCDManager::stop() {
+ DefaultAudioCDManager::stop();
+ stop_cdda();
}
-bool DCCDManager::openCD(int drive)
-{
- // Dummy.
- return true;
+bool DCCDManager::isPlaying() const {
+ if (DefaultAudioCDManager::isPlaying())
+ return true;
+
+ extern int getCdState();
+ return getCdState() == 3;
}
void OSystem_Dreamcast::setWindowCaption(const char *caption)
diff --git a/backends/platform/dingux/README.GCW0 b/backends/platform/dingux/README.GCW0
index 1875e5323a..1b7e30e266 100644
--- a/backends/platform/dingux/README.GCW0
+++ b/backends/platform/dingux/README.GCW0
@@ -24,3 +24,12 @@ It's pretty simple if you are running Linux on an x86/amd64 machine:
3. Run backends/platform/dingux/build.gcw0.sh script
4. Copy the resulting file scummvm.opk to your device
5. Enjoy
+
+Troubleshooting
+===============
+In case you need to submit a bugreport, you may find the log file at the
+following path:
+
+ /var/tmp/scummvm.log
+
+The log file is being overwritten at every ScummVM run.
diff --git a/backends/platform/dingux/build.gcw0.sh b/backends/platform/dingux/build.gcw0.sh
index c4bb9d2641..7a31d4fd27 100755
--- a/backends/platform/dingux/build.gcw0.sh
+++ b/backends/platform/dingux/build.gcw0.sh
@@ -3,4 +3,4 @@
export PATH=/opt/gcw0-toolchain/usr/bin:$PATH
# Disable high resolution engines since we have 320x240 hardware
-./configure --host=gcw0 --enable-plugins --default-dynamic --enable-release --disable-engine=mohawk,neverhood,sword25,toltecs,wintermute,zvision --disable-mt32emu --disable-hq-scalers && make -j6 gcw-opk && ls -l scummvm.opk
+./configure --host=gcw0 --enable-plugins --default-dynamic --enable-release && make -j6 gcw-opk && ls -l scummvm.opk
diff --git a/backends/platform/dingux/dingux.mk b/backends/platform/dingux/dingux.mk
index 56c26c3be1..dc87e41241 100644
--- a/backends/platform/dingux/dingux.mk
+++ b/backends/platform/dingux/dingux.mk
@@ -59,19 +59,20 @@ endif
echo >> $(gcw0_bundle)/README.man.txt
echo '[General README]' >> $(gcw0_bundle)/README.man.txt
echo >> $(gcw0_bundle)/README.man.txt
- cat README >> $(gcw0_bundle)/README.man.txt
+ cat $(srcdir)/README | sed -e 's/\[/⟦/g' -e 's/\]/⟧/g' -e '/^1\.1)/,$$ s/^[0-9][0-9]*\.[0-9][0-9]*.*/\[&\]/' >> $(gcw0_bundle)/README.man.txt
+
# $(CP) GeneralUser\ GS\ FluidSynth\ v1.44.sf2 $(gcw0_bundle)/
gcw0-opk-unstripped: $(gcw0_bundle)
$(CP) $(PLUGINS) $(gcw0_bundle)/plugins/
$(CP) $(EXECUTABLE) $(gcw0_bundle)/scummvm
- ./dists/gcw0/opk_make.sh -d $(gcw0_bundle) -o scummvm
+ $(srcdir)/dists/gcw0/opk_make.sh -d $(gcw0_bundle) -o scummvm
gcw-opk: $(gcw0_bundle)
$(STRIP) $(gcw0_bundle)/plugins/*
$(STRIP) $(gcw0_bundle)/scummvm
- ./dists/gcw0/opk_make.sh -d $(gcw0_bundle) -o scummvm
+ $(srcdir)/dists/gcw0/opk_make.sh -d $(gcw0_bundle) -o scummvm
GeneralUser_GS_1.44-FluidSynth.zip:
curl -s http://www.scummvm.org/frs/extras/SoundFont/GeneralUser_GS_1.44-FluidSynth.zip -o GeneralUser_GS_1.44-FluidSynth.zip
diff --git a/backends/platform/ds/arm9/source/osystem_ds.cpp b/backends/platform/ds/arm9/source/osystem_ds.cpp
index c53f57523d..f23192cd9d 100644
--- a/backends/platform/ds/arm9/source/osystem_ds.cpp
+++ b/backends/platform/ds/arm9/source/osystem_ds.cpp
@@ -715,7 +715,7 @@ void OSystem_DS::deleteMutex(MutexRef mutex) {
// and should be replaced by an AudioCDManager subclass,
// see backends/audiocd/ and common/system.h
-bool OSystem_DS::openCD(int drive) {
+bool OSystem_DS::openCD() {
return DS::CD::checkCD();
}
diff --git a/backends/platform/ds/arm9/source/osystem_ds.h b/backends/platform/ds/arm9/source/osystem_ds.h
index f4dbac66f7..9f73e125c2 100644
--- a/backends/platform/ds/arm9/source/osystem_ds.h
+++ b/backends/platform/ds/arm9/source/osystem_ds.h
@@ -130,7 +130,8 @@ public:
// FIXME/TODO: The CD API as follows is *obsolete*
// and should be replaced by an AudioCDManager subclass,
// see backends/audiocd/ and common/system.h
- virtual bool openCD(int drive);
+ virtual bool openCD();
+ virtual void closeCD() {}
virtual bool pollCD();
virtual void playCD(int track, int num_loops, int start_frame, int duration);
virtual void stopCD();
diff --git a/backends/platform/maemo/debian/changelog b/backends/platform/maemo/debian/changelog
index 6b6d1aebd8..e4c5c58ccd 100644
--- a/backends/platform/maemo/debian/changelog
+++ b/backends/platform/maemo/debian/changelog
@@ -4,6 +4,12 @@ scummvm (1.9.0~git) unstable; urgency=low
-- Tarek Soliman <tsoliman@scummvm.org> Fri, 26 Feb 2016 21:11:20 -0600
+scummvm (1.8.1) unstable; urgency=low
+
+ * 1.8.1 release
+
+ -- Tarek Soliman <tsoliman@scummvm.org> Fri, 20 May 2016 20:05:11 -0500
+
scummvm (1.8.0) unstable; urgency=low
* 1.8.0 release
diff --git a/backends/platform/sdl/amigaos/amigaos-main.cpp b/backends/platform/sdl/amigaos/amigaos-main.cpp
index 65da6bbf85..7bbf8d1fff 100644
--- a/backends/platform/sdl/amigaos/amigaos-main.cpp
+++ b/backends/platform/sdl/amigaos/amigaos-main.cpp
@@ -24,13 +24,44 @@
#if defined(__amigaos4__)
+#include "backends/fs/amigaos4/amigaos4-fs.h"
#include "backends/platform/sdl/amigaos/amigaos.h"
#include "backends/plugins/sdl/sdl-provider.h"
#include "base/main.h"
int main(int argc, char *argv[]) {
- // Set up a stack cookie to avoid crashes due to too few stack set by users
+ // The following will gather the application name and add the install path
+ // to a variable in AmigaOS4's ENV(ARC) system. It will be placed in AppPaths
+ // so that ScummVM can become AmiUpdate aware
+ const char *const appname = "ScummVM";
+
+ BPTR lock;
+ APTR oldwin;
+
+ // Obtain a lock to the home directory
+ if ((lock = IDOS->GetProgramDir())) {
+ TEXT progpath[2048];
+ TEXT apppath[1024] = "AppPaths";
+
+ if (IDOS->DevNameFromLock(lock,
+ progpath,
+ sizeof(progpath),
+ DN_FULLPATH)) {
+
+ // Stop any "Insert volume..." type requesters
+ oldwin = IDOS->SetProcWindow((APTR)-1);
+
+ // Finally, set the variable to the path the executable was run from
+ IDOS->AddPart( apppath, appname, 1024);
+ IDOS->SetVar( apppath, progpath, -1, GVF_GLOBAL_ONLY|GVF_SAVE_VAR );
+
+ // Turn system requesters back on
+ IDOS->SetProcWindow( oldwin );
+ }
+ }
+
+ // Set up a stack cookie to avoid crashes from a stack set too low
static const char *stack_cookie __attribute__((used)) = "$STACK: 600000";
// Create our OSystem instance
@@ -44,7 +75,7 @@ int main(int argc, char *argv[]) {
PluginManager::instance().addPluginProvider(new SDLPluginProvider());
#endif
- // Invoke the actual ScummVM main entry point:
+ // Invoke the actual ScummVM main entry point
int res = scummvm_main(argc, argv);
// Free OSystem
diff --git a/backends/platform/sdl/macosx/macosx.cpp b/backends/platform/sdl/macosx/macosx.cpp
index 38a2d7441c..7652c0d833 100644
--- a/backends/platform/sdl/macosx/macosx.cpp
+++ b/backends/platform/sdl/macosx/macosx.cpp
@@ -27,9 +27,10 @@
#ifdef MACOSX
-#include "backends/platform/sdl/macosx/macosx.h"
+#include "backends/audiocd/macosx/macosx-audiocd.h"
#include "backends/mixer/doublebuffersdl/doublebuffersdl-mixer.h"
#include "backends/platform/sdl/macosx/appmenu_osx.h"
+#include "backends/platform/sdl/macosx/macosx.h"
#include "backends/updates/macosx/macosx-updates.h"
#include "backends/taskbar/macosx/macosx-taskbar.h"
@@ -170,4 +171,8 @@ Common::String OSystem_MacOSX::getSystemLanguage() const {
#endif // USE_DETECTLANG
}
+AudioCDManager *OSystem_MacOSX::createAudioCDManager() {
+ return createMacOSXAudioCDManager();
+}
+
#endif
diff --git a/backends/platform/sdl/macosx/macosx.h b/backends/platform/sdl/macosx/macosx.h
index c8b4beaeec..6905284a5f 100644
--- a/backends/platform/sdl/macosx/macosx.h
+++ b/backends/platform/sdl/macosx/macosx.h
@@ -38,6 +38,11 @@ public:
virtual void init();
virtual void initBackend();
virtual void addSysArchivesToSearchSet(Common::SearchSet &s, int priority = 0);
+
+protected:
+ // Override createAudioCDManager() to get our Mac-specific
+ // version.
+ virtual AudioCDManager *createAudioCDManager();
};
#endif
diff --git a/backends/platform/sdl/posix/posix-main.cpp b/backends/platform/sdl/posix/posix-main.cpp
index d07db11b0c..5deebb0ae3 100644
--- a/backends/platform/sdl/posix/posix-main.cpp
+++ b/backends/platform/sdl/posix/posix-main.cpp
@@ -22,7 +22,7 @@
#include "common/scummsys.h"
-#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3)
+#if defined(POSIX) && !defined(MACOSX) && !defined(SAMSUNGTV) && !defined(MAEMO) && !defined(WEBOS) && !defined(LINUXMOTO) && !defined(GPH_DEVICE) && !defined(GP2X) && !defined(DINGUX) && !defined(OPENPANDORA) && !defined(PLAYSTATION3) && !defined(ANDROIDSDL)
#include "backends/platform/sdl/posix/posix.h"
#include "backends/plugins/sdl/sdl-provider.h"
diff --git a/backends/platform/sdl/posix/posix.cpp b/backends/platform/sdl/posix/posix.cpp
index 525c74a91a..e2a642b288 100644
--- a/backends/platform/sdl/posix/posix.cpp
+++ b/backends/platform/sdl/posix/posix.cpp
@@ -36,6 +36,11 @@
#include "backends/fs/posix/posix-fs.h"
#include "backends/taskbar/unity/unity-taskbar.h"
+#ifdef USE_LINUXCD
+#include "backends/audiocd/linux/linux-audiocd.h"
+#endif
+
+#include <errno.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -239,4 +244,12 @@ bool OSystem_POSIX::displayLogFile() {
}
+AudioCDManager *OSystem_POSIX::createAudioCDManager() {
+#ifdef USE_LINUXCD
+ return createLinuxAudioCDManager();
+#else
+ return OSystem_SDL::createAudioCDManager();
+#endif
+}
+
#endif
diff --git a/backends/platform/sdl/posix/posix.h b/backends/platform/sdl/posix/posix.h
index f67515ddb3..0514d30191 100644
--- a/backends/platform/sdl/posix/posix.h
+++ b/backends/platform/sdl/posix/posix.h
@@ -59,6 +59,8 @@ protected:
virtual Common::String getDefaultConfigFileName();
virtual Common::WriteStream *createLogFile();
+
+ virtual AudioCDManager *createAudioCDManager();
};
#endif
diff --git a/backends/platform/sdl/sdl-sys.h b/backends/platform/sdl/sdl-sys.h
index 219755219f..551605a4b4 100644
--- a/backends/platform/sdl/sdl-sys.h
+++ b/backends/platform/sdl/sdl-sys.h
@@ -52,6 +52,21 @@ typedef struct { int FAKE; } FAKE_FILE;
#define strncasecmp FAKE_strncasecmp
#endif
+#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_exit)
+#undef exit
+#define exit FAKE_exit
+#endif
+
+#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_abort)
+#undef abort
+#define abort FAKE_abort
+#endif
+
+#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_system)
+#undef system
+#define system FAKE_system
+#endif
+
// HACK: SDL might include windows.h which defines its own ARRAYSIZE.
// However, we want to use the version from common/util.h. Thus, we make sure
// that we actually have this definition after including the SDL headers.
@@ -146,6 +161,21 @@ typedef struct { int FAKE; } FAKE_FILE;
#define strncasecmp FORBIDDEN_SYMBOL_REPLACEMENT
#endif
+#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_exit)
+#undef exit
+#define exit(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_abort)
+#undef abort
+#define abort() FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
+#if !defined(FORBIDDEN_SYMBOL_ALLOW_ALL) && !defined(FORBIDDEN_SYMBOL_EXCEPTION_system)
+#undef system
+#define system(a) FORBIDDEN_SYMBOL_REPLACEMENT
+#endif
+
// SDL 2 has major API changes. We redefine constants which got renamed to
// ease the transition. This is sometimes dangerous because the values changed
// too!
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index fffb9d56d9..c55753194b 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -245,15 +245,7 @@ void OSystem_SDL::initBackend() {
_timerManager = new SdlTimerManager();
#endif
- if (_audiocdManager == 0) {
- // Audio CD support was removed with SDL 2.0
-#if SDL_VERSION_ATLEAST(2, 0, 0)
- _audiocdManager = new DefaultAudioCDManager();
-#else
- _audiocdManager = new SdlAudioCDManager();
-#endif
-
- }
+ _audiocdManager = createAudioCDManager();
// Setup a custom program icon.
_window->setupIcon();
@@ -491,6 +483,15 @@ Common::TimerManager *OSystem_SDL::getTimerManager() {
#endif
}
+AudioCDManager *OSystem_SDL::createAudioCDManager() {
+ // Audio CD support was removed with SDL 2.0
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+ return new DefaultAudioCDManager();
+#else
+ return new SdlAudioCDManager();
+#endif
+}
+
#ifdef USE_OPENGL
const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 5ee56d0568..c93c8308a7 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -104,6 +104,11 @@ protected:
*/
virtual void initSDL();
+ /**
+ * Create the audio CD manager
+ */
+ virtual AudioCDManager *createAudioCDManager();
+
// Logging
virtual Common::WriteStream *createLogFile() { return 0; }
Backends::Log::Log *_logger;
diff --git a/backends/platform/sdl/win32/win32.cpp b/backends/platform/sdl/win32/win32.cpp
index 0f70c00b40..fcc0849624 100644
--- a/backends/platform/sdl/win32/win32.cpp
+++ b/backends/platform/sdl/win32/win32.cpp
@@ -35,11 +35,13 @@
#include "common/error.h"
#include "common/textconsole.h"
+#include "backends/audiocd/win32/win32-audiocd.h"
#include "backends/platform/sdl/win32/win32.h"
#include "backends/platform/sdl/win32/win32-window.h"
#include "backends/saves/windows/windows-saves.h"
#include "backends/fs/windows/windows-fs-factory.h"
#include "backends/taskbar/win32/win32-taskbar.h"
+#include "backends/updates/win32/win32-updates.h"
#include "common/memstream.h"
@@ -81,6 +83,11 @@ void OSystem_Win32::initBackend() {
if (_savefileManager == 0)
_savefileManager = new WindowsSaveFileManager();
+#if defined(USE_SPARKLE)
+ // Initialize updates manager
+ _updateManager = new Win32UpdateManager();
+#endif
+
// Invoke parent implementation of this method
OSystem_SDL::initBackend();
}
@@ -318,4 +325,8 @@ void OSystem_Win32::addSysArchivesToSearchSet(Common::SearchSet &s, int priority
OSystem_SDL::addSysArchivesToSearchSet(s, priority);
}
+AudioCDManager *OSystem_Win32::createAudioCDManager() {
+ return createWin32AudioCDManager();
+}
+
#endif
diff --git a/backends/platform/sdl/win32/win32.h b/backends/platform/sdl/win32/win32.h
index 473e78ff0b..ca0843e834 100644
--- a/backends/platform/sdl/win32/win32.h
+++ b/backends/platform/sdl/win32/win32.h
@@ -49,6 +49,10 @@ protected:
virtual Common::String getDefaultConfigFileName();
virtual Common::WriteStream *createLogFile();
+
+ // Override createAudioCDManager() to get our Mac-specific
+ // version.
+ virtual AudioCDManager *createAudioCDManager();
};
#endif
diff --git a/backends/platform/symbian/src/portdefs.h b/backends/platform/symbian/src/portdefs.h
index f9da09d3eb..e2465e4767 100644
--- a/backends/platform/symbian/src/portdefs.h
+++ b/backends/platform/symbian/src/portdefs.h
@@ -65,7 +65,8 @@ typedef signed long int int32;
#undef remove
#endif
-#define SMALL_SCREEN_DEVICE
+#define GUI_ONLY_FULLSCREEN
+#define GUI_ENABLE_KEYSDIALOG
#define DISABLE_COMMAND_LINE
#define USE_RGB_COLOR
diff --git a/backends/platform/tizen/graphics.cpp b/backends/platform/tizen/graphics.cpp
index 759c4e519d..61dbfc38fb 100644
--- a/backends/platform/tizen/graphics.cpp
+++ b/backends/platform/tizen/graphics.cpp
@@ -56,6 +56,7 @@ result TizenGraphicsManager::Construct() {
loadEgl();
// Notify the OpenGL code about our context.
+ setContextType(OpenGL::kContextGLES);
// We default to RGB565 and RGBA5551 which is closest to the actual output
// mode we setup.
@@ -206,3 +207,7 @@ bool TizenGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeig
void TizenGraphicsManager::refreshScreen() {
eglSwapBuffers(_eglDisplay, _eglSurface);
}
+
+void *TizenGraphicsManager::getProcAddress(const char *name) const {
+ return eglGetProcAddress(name);
+}
diff --git a/backends/platform/tizen/graphics.h b/backends/platform/tizen/graphics.h
index 1522d66bbe..1798b078d8 100644
--- a/backends/platform/tizen/graphics.h
+++ b/backends/platform/tizen/graphics.h
@@ -63,6 +63,8 @@ protected:
void refreshScreen();
+ void *getProcAddress(const char *name) const;
+
const Graphics::Font *getFontOSD();
private:
diff --git a/backends/platform/tizen/system.cpp b/backends/platform/tizen/system.cpp
index a235456670..1820a28791 100644
--- a/backends/platform/tizen/system.cpp
+++ b/backends/platform/tizen/system.cpp
@@ -81,36 +81,41 @@ struct TizenSaveFileManager : public DefaultSaveFileManager {
};
bool TizenSaveFileManager::removeSavefile(const Common::String &filename) {
- Common::String savePathName = getSavePath();
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
+ if (getError().getCode() != Common::kNoError)
+ return false;
- checkPath(Common::FSNode(savePathName));
- if (getError().getCode() != Common::kNoError) {
+ // Obtain node if exists.
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ if (file == _saveFileCache.end()) {
return false;
- }
+ } else {
+ const Common::FSNode fileNode = file->_value;
+ // Remove from cache, this invalidates the 'file' iterator.
+ _saveFileCache.erase(file);
+ file = _saveFileCache.end();
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
- Common::FSNode file = savePath.getChild(filename);
+ String unicodeFileName;
+ StringUtil::Utf8ToString(fileNode.getPath().c_str(), unicodeFileName);
- String unicodeFileName;
- StringUtil::Utf8ToString(file.getPath().c_str(), unicodeFileName);
+ switch (Tizen::Io::File::Remove(unicodeFileName)) {
+ case E_SUCCESS:
+ return true;
- switch (Tizen::Io::File::Remove(unicodeFileName)) {
- case E_SUCCESS:
- return true;
+ case E_ILLEGAL_ACCESS:
+ setError(Common::kWritePermissionDenied, "Search or write permission denied: " +
+ file.getName());
+ break;
- case E_ILLEGAL_ACCESS:
- setError(Common::kWritePermissionDenied, "Search or write permission denied: " +
- file.getName());
- break;
+ default:
+ setError(Common::kPathDoesNotExist, "removeSavefile: '" + file.getName() +
+ "' does not exist or path is invalid");
+ break;
+ }
- default:
- setError(Common::kPathDoesNotExist, "removeSavefile: '" + file.getName() +
- "' does not exist or path is invalid");
- break;
+ return false;
}
-
- return false;
}
//
diff --git a/backends/platform/wince/portdefs.h b/backends/platform/wince/portdefs.h
index 3304ee0893..c74fc39169 100644
--- a/backends/platform/wince/portdefs.h
+++ b/backends/platform/wince/portdefs.h
@@ -30,7 +30,8 @@
// Missing string/stdlib/assert declarations for WinCE 2.xx
#if _WIN32_WCE < 300
- #define SMALL_SCREEN_DEVICE
+ #define GUI_ONLY_FULLSCREEN
+ #define GUI_ENABLE_KEYSDIALOG
void *calloc(size_t n, size_t s);
int isalnum(int c);
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 4f7013724a..daec36ae72 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -60,22 +60,15 @@ void DefaultSaveFileManager::checkPath(const Common::FSNode &dir) {
}
Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &pattern) {
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
if (getError().getCode() != Common::kNoError)
return Common::StringArray();
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
-
- Common::FSDirectory dir(savePath);
- Common::ArchiveMemberList savefiles;
Common::StringArray results;
- Common::String search(pattern);
-
- if (dir.listMatchingMembers(savefiles, search) > 0) {
- for (Common::ArchiveMemberList::const_iterator file = savefiles.begin(); file != savefiles.end(); ++file) {
- results.push_back((*file)->getName());
+ for (SaveFileCache::const_iterator file = _saveFileCache.begin(), end = _saveFileCache.end(); file != end; ++file) {
+ if (file->_key.matchString(pattern, true)) {
+ results.push_back(file->_key);
}
}
@@ -83,68 +76,81 @@ Common::StringArray DefaultSaveFileManager::listSavefiles(const Common::String &
}
Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String &filename) {
- // Ensure that the savepath is valid. If not, generate an appropriate error.
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
if (getError().getCode() != Common::kNoError)
- return 0;
-
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
+ return nullptr;
- Common::FSNode file = savePath.getChild(filename);
- if (!file.exists())
- return 0;
-
- // Open the file for reading
- Common::SeekableReadStream *sf = file.createReadStream();
-
- return Common::wrapCompressedReadStream(sf);
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ if (file == _saveFileCache.end()) {
+ return nullptr;
+ } else {
+ // Open the file for loading.
+ Common::SeekableReadStream *sf = file->_value.createReadStream();
+ return Common::wrapCompressedReadStream(sf);
+ }
}
Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename, bool compress) {
- // Ensure that the savepath is valid. If not, generate an appropriate error.
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ const Common::String savePathName = getSavePath();
+ assureCached(savePathName);
if (getError().getCode() != Common::kNoError)
- return 0;
+ return nullptr;
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
+ // Obtain node.
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ Common::FSNode fileNode;
- Common::FSNode file = savePath.getChild(filename);
+ // If the file did not exist before, we add it to the cache.
+ if (file == _saveFileCache.end()) {
+ const Common::FSNode savePath(savePathName);
+ fileNode = savePath.getChild(filename);
+ } else {
+ fileNode = file->_value;
+ }
- // Open the file for saving
- Common::WriteStream *sf = file.createWriteStream();
+ // Open the file for saving.
+ Common::WriteStream *const sf = fileNode.createWriteStream();
+ Common::OutSaveFile *const result = compress ? Common::wrapCompressedWriteStream(sf) : sf;
- return compress ? Common::wrapCompressedWriteStream(sf) : sf;
+ // Add file to cache now that it exists.
+ _saveFileCache[filename] = Common::FSNode(fileNode.getPath());
+
+ return result;
}
bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
- Common::String savePathName = getSavePath();
- checkPath(Common::FSNode(savePathName));
+ // Assure the savefile name cache is up-to-date.
+ assureCached(getSavePath());
if (getError().getCode() != Common::kNoError)
return false;
- // recreate FSNode since checkPath may have changed/created the directory
- Common::FSNode savePath(savePathName);
-
- Common::FSNode file = savePath.getChild(filename);
-
- // FIXME: remove does not exist on all systems. If your port fails to
- // compile because of this, please let us know (scummvm-devel or Fingolfin).
- // There is a nicely portable workaround, too: Make this method overloadable.
- if (remove(file.getPath().c_str()) != 0) {
+ // Obtain node if exists.
+ SaveFileCache::const_iterator file = _saveFileCache.find(filename);
+ if (file == _saveFileCache.end()) {
+ return false;
+ } else {
+ const Common::FSNode fileNode = file->_value;
+ // Remove from cache, this invalidates the 'file' iterator.
+ _saveFileCache.erase(file);
+ file = _saveFileCache.end();
+
+ // FIXME: remove does not exist on all systems. If your port fails to
+ // compile because of this, please let us know (scummvm-devel).
+ // There is a nicely portable workaround, too: Make this method overloadable.
+ if (remove(fileNode.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
- if (errno == EACCES)
- setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());
+ if (errno == EACCES)
+ setError(Common::kWritePermissionDenied, "Search or write permission denied: "+fileNode.getName());
- if (errno == ENOENT)
- setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
+ if (errno == ENOENT)
+ setError(Common::kPathDoesNotExist, "removeSavefile: '"+fileNode.getName()+"' does not exist or path is invalid");
#endif
- return false;
- } else {
- return true;
+ return false;
+ } else {
+ return true;
+ }
}
}
@@ -171,4 +177,43 @@ Common::String DefaultSaveFileManager::getSavePath() const {
return dir;
}
+void DefaultSaveFileManager::assureCached(const Common::String &savePathName) {
+ // Check that path exists and is usable.
+ checkPath(Common::FSNode(savePathName));
+
+ if (_cachedDirectory == savePathName) {
+ return;
+ }
+
+ _saveFileCache.clear();
+ _cachedDirectory.clear();
+
+ if (getError().getCode() != Common::kNoError) {
+ warning("DefaultSaveFileManager::assureCached: Can not cache path '%s': '%s'", savePathName.c_str(), getErrorDesc().c_str());
+ return;
+ }
+
+ // FSNode can cache its members, thus create it after checkPath to reflect
+ // actual file system state.
+ const Common::FSNode savePath(savePathName);
+
+ Common::FSList children;
+ if (!savePath.getChildren(children, Common::FSNode::kListFilesOnly)) {
+ return;
+ }
+
+ // Build the savefile name cache.
+ for (Common::FSList::const_iterator file = children.begin(), end = children.end(); file != end; ++file) {
+ if (_saveFileCache.contains(file->getName())) {
+ warning("DefaultSaveFileManager::assureCached: Name clash when building cache, ignoring file '%s'", file->getName().c_str());
+ } else {
+ _saveFileCache[file->getName()] = *file;
+ }
+ }
+
+ // Only now store that we cached 'savePathName' to indicate we successfully
+ // cached the directory.
+ _cachedDirectory = savePathName;
+}
+
#endif // !defined(DISABLE_DEFAULT_SAVEFILEMANAGER)
diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h
index 81f45f96b8..bf4ca0229d 100644
--- a/backends/saves/default/default-saves.h
+++ b/backends/saves/default/default-saves.h
@@ -27,6 +27,7 @@
#include "common/savefile.h"
#include "common/str.h"
#include "common/fs.h"
+#include "common/hashmap.h"
/**
* Provides a default savefile manager implementation for common platforms.
@@ -54,6 +55,30 @@ protected:
* Sets the internal error and error message accordingly.
*/
virtual void checkPath(const Common::FSNode &dir);
+
+ /**
+ * Assure that the given save path is cached.
+ *
+ * @param savePathName String representation of save path to cache.
+ */
+ void assureCached(const Common::String &savePathName);
+
+ typedef Common::HashMap<Common::String, Common::FSNode, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> SaveFileCache;
+
+ /**
+ * Cache of all the save files in the currently cached directory.
+ *
+ * Modify with caution because we only re-cache when the save path changed!
+ * This needs to be updated inside at least openForSaving and
+ * removeSavefile.
+ */
+ SaveFileCache _saveFileCache;
+
+private:
+ /**
+ * The currently cached directory.
+ */
+ Common::String _cachedDirectory;
};
#endif
diff --git a/backends/taskbar/macosx/dockplugin/dockplugin.m b/backends/taskbar/macosx/dockplugin/dockplugin.m
new file mode 100644
index 0000000000..9d864ef2a8
--- /dev/null
+++ b/backends/taskbar/macosx/dockplugin/dockplugin.m
@@ -0,0 +1,125 @@
+/* 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.
+ *
+ */
+
+#include <Cocoa/Cocoa.h>
+
+@interface ScummVMDockTilePlugIn : NSObject <NSDockTilePlugIn> {
+ NSMenu *recentGamesMenu;
+}
+@end
+
+@interface StartGameMenuItem : NSMenuItem {
+ NSString *game;
+}
+- (IBAction) startGame;
+- (NSMenuItem*)initWithGame:(NSString *)gameId description:(NSString*)desc icon:(NSString*)iconFile;
+@end
+
+@implementation ScummVMDockTilePlugIn
+
+- (id)init {
+ self = [super init];
+ if (self) {
+ recentGamesMenu = nil;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [recentGamesMenu release];
+ [super dealloc];
+}
+
+
+- (void)setDockTile:(NSDockTile *)dockTile {
+}
+
+- (NSMenu*)dockMenu {
+ // Get the list or recent games
+ CFPreferencesAppSynchronize(CFSTR("org.scummvm.scummvm"));
+ NSArray *array = CFPreferencesCopyAppValue(CFSTR("recentGames"), CFSTR("org.scummvm.scummvm"));
+ if (array == nil)
+ return nil;
+
+ // Create the menu
+ if (recentGamesMenu == nil)
+ recentGamesMenu = [[NSMenu alloc] init];
+ else
+ [recentGamesMenu removeAllItems];
+
+ NSEnumerator *enumerator = [array objectEnumerator];
+ NSDictionary *recentGame;
+ while (recentGame = [enumerator nextObject]) {
+ NSString *gameId = [recentGame valueForKey:@"game"];
+ NSString *desc = [recentGame valueForKey:@"description"];
+ NSString *iconFile = [recentGame valueForKey:@"icon"];
+
+ StartGameMenuItem *menuItem = [[StartGameMenuItem alloc] initWithGame:gameId description:desc icon:iconFile];
+ [recentGamesMenu addItem:menuItem];
+ [menuItem release];
+ }
+
+ return recentGamesMenu;
+}
+
+@end
+
+@implementation StartGameMenuItem
+
+- (NSMenuItem*)initWithGame:(NSString *)gameId description:(NSString*)desc icon:(NSString*)iconFile {
+ self = [super initWithTitle:(desc == nil ? gameId : desc) action:@selector(startGame) keyEquivalent:@""];
+ [self setTarget:self];
+
+ if (iconFile != nil) {
+ NSImage *image = [[NSImage alloc] initWithContentsOfFile:iconFile];
+ [self setImage:image];
+ [image release];
+ }
+
+ game = gameId;
+ [game retain];
+
+ return self;
+}
+
+- (void)dealloc {
+ [game release];
+ [super dealloc];
+}
+
+- (IBAction) startGame {
+ NSLog(@"Starting Game %@...", game);
+
+ NSString *scummVMPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:@"org.scummvm.scummvm"];
+ if (scummVMPath == nil) {
+ NSLog(@"Cannot find ScummVM.app!");
+ return;
+ }
+ // Start ScummVM.app with the game ID as argument
+ NSURL *url = [NSURL fileURLWithPath:scummVMPath];
+ NSMutableDictionary *args = [[NSMutableDictionary alloc] init];
+ [args setObject:[NSArray arrayWithObject:game] forKey:NSWorkspaceLaunchConfigurationArguments];
+ [[NSWorkspace sharedWorkspace] launchApplicationAtURL:url options:NSWorkspaceLaunchDefault configuration:args error:nil];
+ [args release];
+}
+
+@end
diff --git a/backends/taskbar/macosx/macosx-taskbar.h b/backends/taskbar/macosx/macosx-taskbar.h
index 5d5b9d02cd..55bb97a691 100644
--- a/backends/taskbar/macosx/macosx-taskbar.h
+++ b/backends/taskbar/macosx/macosx-taskbar.h
@@ -37,6 +37,7 @@ public:
virtual void setProgressValue(int completed, int total);
virtual void setProgressState(TaskbarProgressState state);
virtual void setCount(int count);
+ virtual void addRecent(const Common::String &name, const Common::String &description);
virtual void notifyError();
virtual void clearError();
diff --git a/backends/taskbar/macosx/macosx-taskbar.mm b/backends/taskbar/macosx/macosx-taskbar.mm
index ae087dfb85..c842eb8090 100644
--- a/backends/taskbar/macosx/macosx-taskbar.mm
+++ b/backends/taskbar/macosx/macosx-taskbar.mm
@@ -29,9 +29,6 @@
// NSDockTile was introduced with Mac OS X 10.5.
// Try provide backward compatibility by avoiding NSDockTile symbols.
-// TODO: Implement recent list, maybe as a custom menu on dock tile when app is not running
-// See Dock Tile plug-in at https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/CreatingaDockTilePlug-in/CreatingaDockTilePlug-in.html
-
#include "backends/taskbar/macosx/macosx-taskbar.h"
#include "common/config-manager.h"
#include "common/file.h"
@@ -39,6 +36,9 @@
#include <AppKit/NSApplication.h>
#include <AppKit/NSImage.h>
#include <Foundation/NSString.h>
+#include <Foundation/NSDictionary.h>
+#include <Foundation/NSArray.h>
+#include <Foundation/NSUserDefaults.h>
#include <AppKit/NSImageView.h>
#include <AppKit/NSColor.h>
#include <AppKit/NSBezierPath.h>
@@ -120,7 +120,7 @@ void MacOSXTaskbarManager::setOverlayIcon(const Common::String &name, const Comm
initOverlayIconView();
CFStringRef imageFile = CFStringCreateWithCString(0, path.c_str(), kCFStringEncodingASCII);
- NSImage* image = [[NSImage alloc] initWithContentsOfFile:(NSString *)imageFile];
+ NSImage *image = [[NSImage alloc] initWithContentsOfFile:(NSString *)imageFile];
[_overlayIconView setImage:image];
[image release];
CFRelease(imageFile);
@@ -234,5 +234,64 @@ return (path); \
return "";
}
+void MacOSXTaskbarManager::addRecent(const Common::String &name, const Common::String &description) {
+ //warning("[MacOSXTaskbarManager::addRecent] Adding recent list entry: %s (%s)", name.c_str(), description.c_str());
+
+ if (_dockTile == nil)
+ return;
+
+ // Store the game, description and icon in user preferences.
+ // The NSDockTilePlugin will retrieve them there to list them in the dock tile menu.
+
+ CFStringRef gameName = CFStringCreateWithCString(0, name.c_str(), kCFStringEncodingASCII);
+ CFStringRef desc = CFStringCreateWithCString(0, description.c_str(), kCFStringEncodingASCII);
+
+ // First build the dictionary for this game.
+ NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
+ [dict setObject:(NSString *)gameName forKey:@"game"];
+ [dict setObject:(NSString *)desc forKey:@"description"];
+
+ // Icon
+ Common::String iconPath = getIconPath(name);
+ if (!iconPath.empty()) {
+ CFStringRef icon = CFStringCreateWithCString(0, iconPath.c_str(), kCFStringEncodingASCII);
+ [dict setObject:(NSString *)icon forKey:@"icon"];
+ CFRelease(icon);
+ }
+
+ // Retrieve the current list of recent items and update it.
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSArray *oldArray = [defaults arrayForKey:@"recentGames"];
+ if (oldArray == nil) {
+ [defaults setObject:[NSArray arrayWithObject:dict] forKey:@"recentGames"];
+ } else {
+ NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray];
+ // Insert the new game at the start
+ [newArray insertObject:dict atIndex:0];
+ // If the game was already present in the array, remove it
+ for (unsigned int i = 1 ; i < [newArray count] ; ++i) {
+ NSDictionary *oldDict = [newArray objectAtIndex:i];
+ if (oldDict == nil)
+ continue;
+ NSString *oldGame = [oldDict valueForKey:@"game"];
+ if (oldGame != nil && [oldGame isEqualToString:(NSString*)gameName]) {
+ [newArray removeObjectAtIndex:i];
+ break;
+ }
+ }
+ // And make sure we limit the size of the array to 5 games
+ if ([newArray count] > 5)
+ [newArray removeLastObject];
+ [defaults setObject:newArray forKey:@"recentGames"];
+ [newArray release];
+ }
+
+ // Finally release the dictionary
+ [dict release];
+ CFRelease(gameName);
+ CFRelease(desc);
+}
+
+
#endif
diff --git a/backends/taskbar/win32/win32-taskbar.cpp b/backends/taskbar/win32/win32-taskbar.cpp
index f3339fb917..b2810e55b4 100644
--- a/backends/taskbar/win32/win32-taskbar.cpp
+++ b/backends/taskbar/win32/win32-taskbar.cpp
@@ -85,7 +85,7 @@ const PROPERTYKEY PKEY_Title = { /* fmtid = */ { 0xF29F85E0, 0x4FF9, 0x1068, { 0
Win32TaskbarManager::Win32TaskbarManager(SdlWindow *window) : _window(window), _taskbar(NULL), _count(0), _icon(NULL) {
// Do nothing if not running on Windows 7 or later
- if (!isWin7OrLater())
+ if (!confirmWindowsVersion(10, 0) && !confirmWindowsVersion(6, 1))
return;
CoInitialize(NULL);
@@ -400,14 +400,14 @@ BOOL VerifyVersionInfoFunc(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwType
return verifyVersionInfo(lpVersionInformation, dwTypeMask, dwlConditionMask);
}
-bool Win32TaskbarManager::isWin7OrLater() {
+bool Win32TaskbarManager::confirmWindowsVersion(uint majorVersion, uint minorVersion) {
OSVERSIONINFOEX versionInfo;
DWORDLONG conditionMask = 0;
ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- versionInfo.dwMajorVersion = 6;
- versionInfo.dwMinorVersion = 1;
+ versionInfo.dwMajorVersion = majorVersion;
+ versionInfo.dwMinorVersion = minorVersion;
conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
conditionMask = VerSetConditionMaskFunc(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
diff --git a/backends/taskbar/win32/win32-taskbar.h b/backends/taskbar/win32/win32-taskbar.h
index a6d1b49213..a5c024b21b 100644
--- a/backends/taskbar/win32/win32-taskbar.h
+++ b/backends/taskbar/win32/win32-taskbar.h
@@ -64,7 +64,7 @@ private:
Common::String getIconPath(Common::String target);
// Helper functions
- bool isWin7OrLater();
+ bool confirmWindowsVersion(uint majorVersion, uint minorVersion);
LPWSTR ansiToUnicode(const char *s);
HWND getHwnd();
};
diff --git a/backends/updates/macosx/macosx-updates.h b/backends/updates/macosx/macosx-updates.h
index fd2d1f46f5..6fb9af7712 100644
--- a/backends/updates/macosx/macosx-updates.h
+++ b/backends/updates/macosx/macosx-updates.h
@@ -39,8 +39,10 @@ public:
virtual void setAutomaticallyChecksForUpdates(UpdateState state);
virtual UpdateState getAutomaticallyChecksForUpdates();
- virtual void setUpdateCheckInterval(UpdateInterval interval);
- virtual UpdateInterval getUpdateCheckInterval();
+ virtual void setUpdateCheckInterval(int interval);
+ virtual int getUpdateCheckInterval();
+
+ virtual bool getLastUpdateCheckTimeAndDate(TimeDate &t);
};
#endif
diff --git a/backends/updates/macosx/macosx-updates.mm b/backends/updates/macosx/macosx-updates.mm
index a94f1c21fd..db9362a459 100644
--- a/backends/updates/macosx/macosx-updates.mm
+++ b/backends/updates/macosx/macosx-updates.mm
@@ -23,14 +23,18 @@
// Disable symbol overrides so that we can use system headers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/system.h"
#include "backends/updates/macosx/macosx-updates.h"
#ifdef USE_SPARKLE
#include "common/translation.h"
+#include "common/config-manager.h"
#include <Cocoa/Cocoa.h>
#include <Sparkle/Sparkle.h>
+#include <AvailabilityMacros.h>
+
SUUpdater *sparkleUpdater;
/**
@@ -45,14 +49,22 @@ SUUpdater *sparkleUpdater;
*
*/
MacOSXUpdateManager::MacOSXUpdateManager() {
+ NSBundle* mainBundle = [NSBundle mainBundle];
+
+ NSString *version = [mainBundle objectForInfoDictionaryKey:(__bridge NSString *)kCFBundleVersionKey];
+ if (!version || [version isEqualToString:@""]) {
+ warning("Running not in bundle, skipping Sparkle initialization");
+
+ sparkleUpdater = nullptr;
+ return;
+ }
+
NSMenuItem *menuItem = [[NSApp mainMenu] itemAtIndex:0];
NSMenu *applicationMenu = [menuItem submenu];
// Init Sparkle
sparkleUpdater = [SUUpdater sharedUpdater];
- NSBundle* mainBundle = [NSBundle mainBundle];
-
NSString* feedbackURL = [mainBundle objectForInfoDictionaryKey:@"SUFeedURL"];
// Set appcast URL
@@ -74,11 +86,13 @@ MacOSXUpdateManager::MacOSXUpdateManager() {
// Finally give up our references to the objects
[menuItem release];
- // Enable automatic update checking once a day (alternatively use
- // checkForUpdates() here to check for updates on every startup)
- // TODO: Should be removed when an update settings gui is implemented
- setAutomaticallyChecksForUpdates(kUpdateStateEnabled);
- setUpdateCheckInterval(kUpdateIntervalOneDay);
+ if (!ConfMan.hasKey("updates_check")
+ || ConfMan.getInt("updates_check") == Common::UpdateManager::kUpdateIntervalNotSupported) {
+ setAutomaticallyChecksForUpdates(kUpdateStateDisabled);
+ } else {
+ setAutomaticallyChecksForUpdates(kUpdateStateEnabled);
+ setUpdateCheckInterval(normalizeInterval(ConfMan.getInt("updates_check")));
+ }
}
MacOSXUpdateManager::~MacOSXUpdateManager() {
@@ -86,6 +100,9 @@ MacOSXUpdateManager::~MacOSXUpdateManager() {
}
void MacOSXUpdateManager::checkForUpdates() {
+ if (sparkleUpdater == nullptr)
+ return;
+
[sparkleUpdater checkForUpdatesInBackground];
}
@@ -93,24 +110,38 @@ void MacOSXUpdateManager::setAutomaticallyChecksForUpdates(UpdateManager::Update
if (state == kUpdateStateNotSupported)
return;
+ if (sparkleUpdater == nullptr)
+ return;
+
[sparkleUpdater setAutomaticallyChecksForUpdates:(state == kUpdateStateEnabled ? YES : NO)];
}
Common::UpdateManager::UpdateState MacOSXUpdateManager::getAutomaticallyChecksForUpdates() {
+ if (sparkleUpdater == nullptr)
+ return kUpdateStateDisabled;
+
if ([sparkleUpdater automaticallyChecksForUpdates])
return kUpdateStateEnabled;
else
return kUpdateStateDisabled;
}
-void MacOSXUpdateManager::setUpdateCheckInterval(UpdateInterval interval) {
+void MacOSXUpdateManager::setUpdateCheckInterval(int interval) {
+ if (sparkleUpdater == nullptr)
+ return;
+
if (interval == kUpdateIntervalNotSupported)
return;
+ interval = normalizeInterval(interval);
+
[sparkleUpdater setUpdateCheckInterval:(NSTimeInterval)interval];
}
-Common::UpdateManager::UpdateInterval MacOSXUpdateManager::getUpdateCheckInterval() {
+int MacOSXUpdateManager::getUpdateCheckInterval() {
+ if (sparkleUpdater == nullptr)
+ return kUpdateIntervalOneDay;
+
// This is kind of a hack but necessary, as the value stored by Sparkle
// might have been changed outside of ScummVM (in which case we return the
// default interval of one day)
@@ -128,4 +159,30 @@ Common::UpdateManager::UpdateInterval MacOSXUpdateManager::getUpdateCheckInterva
}
}
+bool MacOSXUpdateManager::getLastUpdateCheckTimeAndDate(TimeDate &t) {
+ if (sparkleUpdater == nullptr)
+ return false;
+
+ NSDate *date = [sparkleUpdater lastUpdateCheckDate];
+#ifdef MAC_OS_X_VERSION_10_10
+ NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
+ NSDateComponents *components = [gregorian components:(NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:date];
+#else
+ NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+ NSDateComponents *components = [gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:date];
+#endif
+
+ t.tm_wday = [components weekday];
+ t.tm_year = [components year];
+ t.tm_mon = [components month];
+ t.tm_mday = [components day];
+ t.tm_hour = [components hour];
+ t.tm_min = [components minute];
+ t.tm_sec = [components second];
+
+ [gregorian release];
+
+ return true;
+}
+
#endif
diff --git a/backends/updates/win32/win32-updates.cpp b/backends/updates/win32/win32-updates.cpp
new file mode 100644
index 0000000000..356ff9c903
--- /dev/null
+++ b/backends/updates/win32/win32-updates.cpp
@@ -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.
+ *
+ */
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+
+#include "common/system.h"
+#include "backends/updates/win32/win32-updates.h"
+
+#ifdef USE_SPARKLE
+#include "common/translation.h"
+#include "common/config-manager.h"
+
+#include <time.h>
+#include <winsparkle.h>
+
+/**
+ * Sparkle is a software update framework for Mac OS X which uses appcasts for
+ * release information. Appcasts are RSS-like XML feeds which contain information
+ * about the most current version at the time. If a new version is available, the
+ * user is presented the release-notes/changes/fixes and is asked if he wants to
+ * update, and if yes the Sparkle framework downloads a signed update package
+ * from the server and automatically installs and restarts the software.
+ * More detailed information is available at the following address:
+ * http://sparkle.andymatuschak.org/
+ *
+ * WinSparkle is a heavily (to the point of being its almost-port) inspired by the
+ * Sparkle framework originally by Andy Matuschak that became the de facto standard
+ * for software updates on OS X.
+ * More detailed information is available at the following address:
+ * https://winsparkle.org/
+ *
+ */
+Win32UpdateManager::Win32UpdateManager() {
+ const char *appcastUrl = "https://www.scummvm.org/appcasts/macosx/release.xml";
+
+ win_sparkle_set_appcast_url(appcastUrl);
+ win_sparkle_init();
+
+ if (!ConfMan.hasKey("updates_check")
+ || ConfMan.getInt("updates_check") == Common::UpdateManager::kUpdateIntervalNotSupported) {
+ setAutomaticallyChecksForUpdates(kUpdateStateDisabled);
+ } else {
+ setAutomaticallyChecksForUpdates(kUpdateStateEnabled);
+ setUpdateCheckInterval(normalizeInterval(ConfMan.getInt("updates_check")));
+ }
+}
+
+Win32UpdateManager::~Win32UpdateManager() {
+ win_sparkle_cleanup();
+}
+
+void Win32UpdateManager::checkForUpdates() {
+ win_sparkle_check_update_with_ui();
+}
+
+void Win32UpdateManager::setAutomaticallyChecksForUpdates(UpdateManager::UpdateState state) {
+ if (state == kUpdateStateNotSupported)
+ return;
+
+ win_sparkle_set_automatic_check_for_updates(state == kUpdateStateEnabled ? 1 : 0);
+}
+
+Common::UpdateManager::UpdateState Win32UpdateManager::getAutomaticallyChecksForUpdates() {
+ if (win_sparkle_get_automatic_check_for_updates() == 1)
+ return kUpdateStateEnabled;
+ else
+ return kUpdateStateDisabled;
+}
+
+void Win32UpdateManager::setUpdateCheckInterval(int interval) {
+ if (interval == kUpdateIntervalNotSupported)
+ return;
+
+ interval = normalizeInterval(interval);
+
+ win_sparkle_set_update_check_interval(interval);
+}
+
+int Win32UpdateManager::getUpdateCheckInterval() {
+ // This is kind of a hack but necessary, as the value stored by Sparkle
+ // might have been changed outside of ScummVM (in which case we return the
+ // default interval of one day)
+
+ int updateInterval = win_sparkle_get_update_check_interval();
+ switch (updateInterval) {
+ case kUpdateIntervalOneDay:
+ case kUpdateIntervalOneWeek:
+ case kUpdateIntervalOneMonth:
+ return updateInterval;
+
+ default:
+ // Return the default value (one day)
+ return kUpdateIntervalOneDay;
+ }
+}
+
+bool Win32UpdateManager::getLastUpdateCheckTimeAndDate(TimeDate &t) {
+ time_t updateTime = win_sparkle_get_last_check_time();
+ tm *ut = localtime(&updateTime);
+
+ t.tm_wday = ut->tm_wday;
+ t.tm_year = ut->tm_year;
+ t.tm_mon = ut->tm_mon;
+ t.tm_mday = ut->tm_mday;
+ t.tm_hour = ut->tm_hour;
+ t.tm_min = ut->tm_min;
+ t.tm_sec = ut->tm_sec;
+
+ return true;
+}
+
+#endif
diff --git a/backends/updates/win32/win32-updates.h b/backends/updates/win32/win32-updates.h
new file mode 100644
index 0000000000..71ed9ef685
--- /dev/null
+++ b/backends/updates/win32/win32-updates.h
@@ -0,0 +1,50 @@
+/* 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.
+ *
+ */
+
+#ifndef BACKENDS_UPDATES_WIN32_H
+#define BACKENDS_UPDATES_WIN32_H
+
+#include "common/scummsys.h"
+
+#if defined(WIN32) && defined(USE_SPARKLE)
+
+#include "common/updates.h"
+
+class Win32UpdateManager : public Common::UpdateManager {
+public:
+ Win32UpdateManager();
+ virtual ~Win32UpdateManager();
+
+ virtual void checkForUpdates();
+
+ virtual void setAutomaticallyChecksForUpdates(UpdateState state);
+ virtual UpdateState getAutomaticallyChecksForUpdates();
+
+ virtual void setUpdateCheckInterval(int interval);
+ virtual int getUpdateCheckInterval();
+
+ virtual bool getLastUpdateCheckTimeAndDate(TimeDate &t);
+};
+
+#endif
+
+#endif // BACKENDS_UPDATES_WIN32_H
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 19702ea36d..2c24c018ee 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -57,7 +57,7 @@ static const char USAGE_STRING[] =
;
// DONT FIXME: DO NOT ORDER ALPHABETICALLY, THIS IS ORDERED BY IMPORTANCE/CATEGORY! :)
-#if defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) || defined(__DS__)
+#if defined(__SYMBIAN32__) || defined(__GP32__) || defined(ANDROID) || defined(__DS__) || defined(__3DS__)
static const char HELP_STRING[] = "NoUsageString"; // save more data segment space
#else
static const char HELP_STRING[] =
@@ -100,8 +100,9 @@ static const char HELP_STRING[] =
" -u, --dump-scripts Enable script dumping if a directory called 'dumps'\n"
" exists in the current directory\n"
"\n"
- " --cdrom=NUM CD drive to play CD audio from (default: 0 = first\n"
- " drive)\n"
+ " --cdrom=DRIVE CD drive to play CD audio from; can either be a\n"
+ " drive, path, or numeric index (default: 0 = best\n"
+ " choice drive)\n"
" --joystick[=NUM] Enable joystick input (default: 0 = first joystick)\n"
" --platform=WORD Specify platform of game (allowed values: 2gs, 3do,\n"
" acorn, amiga, atari, c64, fmtowns, nes, mac, pc, pc98,\n"
@@ -373,6 +374,12 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
// We defer checking whether this is a valid target to a later point.
return s;
} else {
+ // On MacOS X prior to 10.9 the OS is sometimes adding a -psn_X_XXXXXX argument (where X are digits)
+ // to pass the process serial number. We need to ignore it to avoid an error.
+#ifdef MACOSX
+ if (strncmp(s, "-psn_", 5) == 0)
+ continue;
+#endif
bool isLongCmd = (s[0] == '-' && s[1] == '-');
diff --git a/base/main.cpp b/base/main.cpp
index ff441df49c..349f719ed5 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -75,6 +75,9 @@
#include "gui/launcher.h"
#endif
+#ifdef USE_UPDATES
+#include "gui/updates-dialog.h"
+#endif
static bool launcherDialog() {
@@ -148,8 +151,11 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
#endif
// Verify that the game path refers to an actual directory
- if (!(dir.exists() && dir.isDirectory()))
+ if (!dir.exists()) {
+ err = Common::kPathDoesNotExist;
+ } else if (!dir.isDirectory()) {
err = Common::kPathNotDirectory;
+ }
// Create the game engine
if (err.getCode() == Common::kNoError) {
@@ -382,7 +388,8 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
if (settings.contains("debugflags")) {
specialDebug = settings["debugflags"];
settings.erase("debugflags");
- }
+ } else if (ConfMan.hasKey("debugflags"))
+ specialDebug = ConfMan.get("debugflags");
PluginManager::instance().init();
PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager
@@ -458,6 +465,13 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
// Now as the event manager is created, setup the keymapper
setupKeymapper(system);
+#ifdef USE_UPDATES
+ if (!ConfMan.hasKey("updates_check")) {
+ GUI::UpdatesDialog dlg;
+ dlg.runModal();
+ }
+#endif
+
// Unless a game was specified, show the launcher dialog
if (0 == ConfMan.getActiveDomain())
launcherDialog();
diff --git a/base/version.cpp b/base/version.cpp
index fcb2740de9..299e4ce325 100644
--- a/base/version.cpp
+++ b/base/version.cpp
@@ -51,7 +51,7 @@
* header file, analog to internal_version.h, maybe called svn_rev.h or so.)
*
* Drawback: This only works on systems which can run suitable scripts as part
- * of the build proces (so I guess Visual C++ would be out of the game here?
+ * of the build process (so I guess Visual C++ would be out of the game here?
* I don't know VC enough to be sure). And of course it must be robust enough
* to properly work in exports (i.e. release tar balls etc.).
*/
diff --git a/common/algorithm.h b/common/algorithm.h
index cbd6eae708..13cdd9f991 100644
--- a/common/algorithm.h
+++ b/common/algorithm.h
@@ -270,5 +270,26 @@ T gcd(T a, T b) {
#pragma warning(pop)
#endif
+/**
+ * Replacement algorithm for iterables.
+ *
+ * Replaces all occurrences of "original" in [begin, end) with occurrences of "replaced".
+ *
+ * @param[in, out] begin: First element to be examined.
+ * @param[in] end: Last element in the seubsection. Not examined.
+ * @param[in] original: Elements to be replaced.
+ * @param[in] replaced: Element to replace occurrences of "original".
+ *
+ * @note Usage examples and unit tests may be found in "test/common/algorithm.h"
+ */
+template<class It, class Dat>
+void replace(It begin, It end, const Dat &original, const Dat &replaced) {
+ for (; begin != end; ++begin) {
+ if (*begin == original) {
+ *begin = replaced;
+ }
+ }
+}
+
} // End of namespace Common
#endif
diff --git a/common/array.h b/common/array.h
index db1a62ba34..04ec9f9ccb 100644
--- a/common/array.h
+++ b/common/array.h
@@ -361,6 +361,87 @@ protected:
};
+/**
+ * Double linked list with sorted nodes.
+ */
+template<class T>
+class SortedArray : public Array<T> {
+public:
+ typedef T *iterator;
+ typedef uint size_type;
+
+ SortedArray(int (*comparator)(const void *, const void *)) {
+ _comparator = comparator;
+ }
+
+ /**
+ * Inserts element at the sorted position.
+ */
+ void insert(const T &element) {
+ if (!this->_size) {
+ this->insert_aux(this->_storage, &element, &element + 1);
+ return;
+ }
+
+ T *where = bsearchMin(element);
+
+ if (where > this->_storage + this->_size)
+ Array<T>::push_back(element);
+ else
+ Array<T>::insert(where, element);
+ }
+
+ T &operator[](size_type idx) {
+ error("Operation []= not allowed with SortedArray");
+ }
+
+ void insert_at(size_type idx, const T &element) {
+ error("Operation insert_at(idx, element) not allowed with SortedArray");
+ }
+
+ void insert_at(size_type idx, const Array<T> &array) {
+ error("Operation insert_at(idx, array) not allowed with SortedArray");
+ }
+
+ void insert(iterator pos, const T &element) {
+ error("Operation insert(pos, elemnet) not allowed with SortedArray");
+ }
+
+ void push_back(const T &element) {
+ error("Operation push_back(element) not allowed with SortedArray");
+ }
+
+ void push_back(const Array<T> &array) {
+ error("Operation push_back(array) not allowed with SortedArray");
+ }
+
+private:
+ // Based on code Copyright (C) 2008-2009 Ksplice, Inc.
+ // Author: Tim Abbott <tabbott@ksplice.com>
+ // Licensed under GPLv2+
+ T *bsearchMin(void *key) {
+ uint start_ = 0, end_ = this->_size;
+ int result;
+
+ while (start_ < end_) {
+ uint mid = start_ + (end_ - start_) / 2;
+
+ result = this->_comparator(key, this->_storage[mid]);
+ if (result < 0)
+ end_ = mid;
+ else if (result > 0)
+ start_ = mid + 1;
+ else
+ return &this->_storage[mid];
+ }
+
+ return &this->_storage[start_];
+ }
+
+private:
+ int (*_comparator)(const void *, const void *);
+};
+
} // End of namespace Common
#endif
diff --git a/common/gui_options.cpp b/common/gui_options.cpp
index 473f78c795..df880f4fee 100644
--- a/common/gui_options.cpp
+++ b/common/gui_options.cpp
@@ -74,6 +74,7 @@ const struct GameOpt {
{ GUIO_GAMEOPTIONS6, "gameOption6" },
{ GUIO_GAMEOPTIONS7, "gameOption7" },
{ GUIO_GAMEOPTIONS8, "gameOption8" },
+ { GUIO_GAMEOPTIONS9, "gameOption9" },
{ GUIO_NONE, 0 }
};
diff --git a/common/gui_options.h b/common/gui_options.h
index aa15d906f5..ec3eccd161 100644
--- a/common/gui_options.h
+++ b/common/gui_options.h
@@ -68,6 +68,7 @@
#define GUIO_GAMEOPTIONS6 "\055"
#define GUIO_GAMEOPTIONS7 "\056"
#define GUIO_GAMEOPTIONS8 "\057"
+#define GUIO_GAMEOPTIONS9 "\058"
#define GUIO0() (GUIO_NONE)
#define GUIO1(a) (a)
diff --git a/common/macresman.cpp b/common/macresman.cpp
index d83bde8fd8..adca1ea10b 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -29,6 +29,7 @@
#include "common/md5.h"
#include "common/substream.h"
#include "common/textconsole.h"
+#include "common/archive.h"
#ifdef MACOSX
#include "common/config-manager.h"
@@ -261,6 +262,76 @@ bool MacResManager::exists(const String &fileName) {
return false;
}
+void MacResManager::listFiles(StringArray &files, const String &pattern) {
+ // Base names discovered so far.
+ typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> BaseNameSet;
+ BaseNameSet baseNames;
+
+ // List files itself.
+ ArchiveMemberList memberList;
+ SearchMan.listMatchingMembers(memberList, pattern);
+ SearchMan.listMatchingMembers(memberList, pattern + ".rsrc");
+ SearchMan.listMatchingMembers(memberList, pattern + ".bin");
+ SearchMan.listMatchingMembers(memberList, constructAppleDoubleName(pattern));
+
+ for (ArchiveMemberList::const_iterator i = memberList.begin(), end = memberList.end(); i != end; ++i) {
+ String filename = (*i)->getName();
+
+ // For raw resource forks and MacBinary files we strip the extension
+ // here to obtain a valid base name.
+ int lastDotPos = filename.size() - 1;
+ for (; lastDotPos >= 0; --lastDotPos) {
+ if (filename[lastDotPos] == '.') {
+ break;
+ }
+ }
+
+ if (lastDotPos != -1) {
+ const char *extension = filename.c_str() + lastDotPos + 1;
+ bool removeExtension = false;
+
+ // TODO: Should we really keep filenames suggesting raw resource
+ // forks or MacBinary files but not being such around? This might
+ // depend on the pattern the client requests...
+ if (!scumm_stricmp(extension, "rsrc")) {
+ SeekableReadStream *stream = (*i)->createReadStream();
+ removeExtension = stream && isRawFork(*stream);
+ delete stream;
+ } else if (!scumm_stricmp(extension, "bin")) {
+ SeekableReadStream *stream = (*i)->createReadStream();
+ removeExtension = stream && isMacBinary(*stream);
+ delete stream;
+ }
+
+ if (removeExtension) {
+ filename.erase(lastDotPos);
+ }
+ }
+
+ // Strip AppleDouble '._' prefix if applicable.
+ bool isAppleDoubleName = false;
+ const String filenameAppleDoubleStripped = disassembleAppleDoubleName(filename, &isAppleDoubleName);
+
+ if (isAppleDoubleName) {
+ SeekableReadStream *stream = (*i)->createReadStream();
+ if (stream->readUint32BE() == 0x00051607) {
+ filename = filenameAppleDoubleStripped;
+ }
+ // TODO: Should we really keep filenames suggesting AppleDouble
+ // but not being AppleDouble around? This might depend on the
+ // pattern the client requests...
+ delete stream;
+ }
+
+ baseNames[filename] = true;
+ }
+
+ // Append resulting base names to list to indicate found files.
+ for (BaseNameSet::const_iterator i = baseNames.begin(), end = baseNames.end(); i != end; ++i) {
+ files.push_back(i->_key);
+ }
+}
+
bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) {
if (stream.readUint32BE() != 0x00051607) // tag
return false;
@@ -314,6 +385,18 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) {
return true;
}
+bool MacResManager::isRawFork(SeekableReadStream &stream) {
+ // TODO: Is there a better way to detect whether this is a raw fork?
+ const uint32 dataOffset = stream.readUint32BE();
+ const uint32 mapOffset = stream.readUint32BE();
+ const uint32 dataLength = stream.readUint32BE();
+ const uint32 mapLength = stream.readUint32BE();
+
+ return !stream.eos() && !stream.err()
+ && dataOffset < (uint32)stream.size() && dataOffset + dataLength <= (uint32)stream.size()
+ && mapOffset < (uint32)stream.size() && mapOffset + mapLength <= (uint32)stream.size();
+}
+
bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) {
byte infoHeader[MBI_INFOHDR];
stream.read(infoHeader, MBI_INFOHDR);
@@ -592,4 +675,32 @@ String MacResManager::constructAppleDoubleName(String name) {
return name;
}
+String MacResManager::disassembleAppleDoubleName(String name, bool *isAppleDouble) {
+ if (isAppleDouble) {
+ *isAppleDouble = false;
+ }
+
+ // Remove "._" before the last portion of a path name.
+ for (int i = name.size() - 1; i >= 0; --i) {
+ if (i == 0) {
+ if (name.size() > 2 && name[0] == '.' && name[1] == '_') {
+ name.erase(0, 2);
+ if (isAppleDouble) {
+ *isAppleDouble = true;
+ }
+ }
+ } else if (name[i] == '/') {
+ if ((uint)(i + 2) < name.size() && name[i + 1] == '.' && name[i + 2] == '_') {
+ name.erase(i + 1, 2);
+ if (isAppleDouble) {
+ *isAppleDouble = true;
+ }
+ }
+ break;
+ }
+ }
+
+ return name;
+}
+
} // End of namespace Common
diff --git a/common/macresman.h b/common/macresman.h
index 43ec8d8e2c..05b2a875f4 100644
--- a/common/macresman.h
+++ b/common/macresman.h
@@ -33,6 +33,7 @@
#include "common/array.h"
#include "common/fs.h"
#include "common/str.h"
+#include "common/str-array.h"
#ifndef COMMON_MACRESMAN_H
#define COMMON_MACRESMAN_H
@@ -82,6 +83,16 @@ public:
static bool exists(const String &fileName);
/**
+ * List all filenames matching pattern for opening with open().
+ *
+ * @param files Array containing all matching filenames discovered. Only
+ * adds to the list.
+ * @param pattern Pattern to match against. Taking String::matchPattern's
+ * format.
+ */
+ static void listFiles(StringArray &files, const String &pattern);
+
+ /**
* Close the Mac data/resource fork pair.
*/
void close();
@@ -176,6 +187,7 @@ private:
bool loadFromAppleDouble(SeekableReadStream &stream);
static String constructAppleDoubleName(String name);
+ static String disassembleAppleDoubleName(String name, bool *isAppleDouble);
/**
* Check if the given stream is in the MacBinary format.
@@ -183,6 +195,13 @@ private:
*/
static bool isMacBinary(SeekableReadStream &stream);
+ /**
+ * Do a sanity check whether the given stream is a raw resource fork.
+ *
+ * @param stream Stream object to check. Will not preserve its position.
+ */
+ static bool isRawFork(SeekableReadStream &stream);
+
enum {
kResForkNone = 0,
kResForkRaw,
diff --git a/common/memstream.h b/common/memstream.h
index 5ecc553454..94407f5cc9 100644
--- a/common/memstream.h
+++ b/common/memstream.h
@@ -25,6 +25,7 @@
#include "common/stream.h"
#include "common/types.h"
+#include "common/util.h"
namespace Common {
@@ -156,7 +157,7 @@ public:
* that grows as it's written to.
*/
class MemoryWriteStreamDynamic : public WriteStream {
-private:
+protected:
uint32 _capacity;
uint32 _size;
byte *_ptr;
@@ -170,7 +171,7 @@ private:
byte *old_data = _data;
- _capacity = new_len + 32;
+ _capacity = MAX(new_len + 32, _capacity * 2);
_data = (byte *)malloc(_capacity);
_ptr = _data + _pos;
diff --git a/common/module.mk b/common/module.mk
index 67c498df00..570040c8e1 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -56,5 +56,10 @@ MODULE_OBJS += \
recorderfile.o
endif
+ifdef USE_UPDATES
+MODULE_OBJS += \
+ updates.o
+endif
+
# Include common rules
include $(srcdir)/rules.mk
diff --git a/common/platform.cpp b/common/platform.cpp
index 636c1ddb52..280185d862 100644
--- a/common/platform.cpp
+++ b/common/platform.cpp
@@ -27,6 +27,7 @@ namespace Common {
const PlatformDescription g_platforms[] = {
{ "2gs", "2gs", "2gs", "Apple IIgs", kPlatformApple2GS },
+ { "apple2", "apple2", "apple2", "Apple II", kPlatformApple2 },
{ "3do", "3do", "3do", "3DO", kPlatform3DO },
{ "acorn", "acorn", "acorn", "Acorn", kPlatformAcorn },
{ "amiga", "ami", "amiga", "Amiga", kPlatformAmiga },
diff --git a/common/platform.h b/common/platform.h
index 17a332b851..15bcddb62e 100644
--- a/common/platform.h
+++ b/common/platform.h
@@ -50,6 +50,7 @@ enum Platform {
kPlatformSegaCD,
kPlatform3DO,
kPlatformPCEngine,
+ kPlatformApple2,
kPlatformApple2GS,
kPlatformPC98,
kPlatformWii,
diff --git a/common/recorderfile.cpp b/common/recorderfile.cpp
index 71f8272b44..04802aa0c8 100644
--- a/common/recorderfile.cpp
+++ b/common/recorderfile.cpp
@@ -30,6 +30,8 @@
#include "graphics/surface.h"
#include "graphics/scaler.h"
+#ifdef ENABLE_EVENTRECORDER
+
#define RECORD_VERSION 1
namespace Common {
@@ -714,3 +716,5 @@ void PlaybackFile::checkRecordedMD5() {
}
+
+#endif // ENABLE_EVENTRECORDER
diff --git a/common/rect.h b/common/rect.h
index 32424d3e6a..e6534e55d3 100644
--- a/common/rect.h
+++ b/common/rect.h
@@ -163,7 +163,8 @@ struct Rect {
*
* @param r the rectangle to check
*
- * @return true if the given rectangle is inside the rectangle, false otherwise
+ * @return true if the given rectangle has a non-empty intersection with
+ * this rectangle, false otherwise
*/
bool intersects(const Rect &r) const {
return (left < r.right) && (r.left < right) && (top < r.bottom) && (r.top < bottom);
diff --git a/common/savefile.h b/common/savefile.h
index b0c4d31f53..9fca07f9d5 100644
--- a/common/savefile.h
+++ b/common/savefile.h
@@ -56,6 +56,12 @@ typedef WriteStream OutSaveFile;
* i.e. typically save states, but also configuration files and similar
* things.
*
+ * Savefile names represent SaveFiles. These names are case insensitive, that
+ * means a name of "Kq1.000" represents the same savefile as "kq1.000". In
+ * addition, SaveFileManager does not allow for names which contain path
+ * separators like '/' or '\'. This is because we do not support directories
+ * in SaveFileManager.
+ *
* While not declared as a singleton, it is effectively used as such,
* with OSystem::getSavefileManager returning a pointer to the single
* SaveFileManager instances to be used.
@@ -115,49 +121,56 @@ public:
* exports from the Quest for Glory series. QfG5 is a 3D game and won't be
* supported by ScummVM.
*
- * @param name the name of the savefile
- * @param compress toggles whether to compress the resulting save file
- * (default) or not.
- * @return pointer to an OutSaveFile, or NULL if an error occurred.
+ * @param name The name of the savefile.
+ * @param compress Toggles whether to compress the resulting save file
+ * (default) or not.
+ * @return Pointer to an OutSaveFile, or NULL if an error occurred.
*/
virtual OutSaveFile *openForSaving(const String &name, bool compress = true) = 0;
/**
* Open the file with the specified name in the given directory for loading.
- * @param name the name of the savefile
- * @return pointer to an InSaveFile, or NULL if an error occurred.
+ *
+ * @param name The name of the savefile.
+ * @return Pointer to an InSaveFile, or NULL if an error occurred.
*/
virtual InSaveFile *openForLoading(const String &name) = 0;
/**
* Removes the given savefile from the system.
- * @param name the name of the savefile to be removed.
+ *
+ * @param name The name of the savefile to be removed.
* @return true if no error occurred, false otherwise.
*/
virtual bool removeSavefile(const String &name) = 0;
/**
* Renames the given savefile.
- * @param oldName Old name.
- * @param newName New name.
+ *
+ * @param oldName Old name.
+ * @param newName New name.
* @return true if no error occurred. false otherwise.
*/
virtual bool renameSavefile(const String &oldName, const String &newName);
/**
* Copy the given savefile.
- * @param oldName Old name.
- * @param newName New name.
+ *
+ * @param oldName Old name.
+ * @param newName New name.
* @return true if no error occurred. false otherwise.
*/
virtual bool copySavefile(const String &oldName, const String &newName);
/**
- * Request a list of available savegames with a given DOS-style pattern,
- * also known as "glob" in the POSIX world. Refer to the Common::matchString()
- * function to learn about the precise pattern format.
- * @param pattern Pattern to match. Wildcards like * or ? are available.
- * @return list of strings for all present file names.
+ * List available savegames matching a given pattern.
+ *
+ * Our pattern format is based on DOS paterns, also known as "glob" in the
+ * POSIX world. Please refer to the Common::matchString() function to learn
+ * about the precise pattern format.
+ *
+ * @param pattern Pattern to match. Wildcards like * or ? are available.
+ * @return List of strings for all present file names.
* @see Common::matchString()
*/
virtual StringArray listSavefiles(const String &pattern) = 0;
diff --git a/common/scummsys.h b/common/scummsys.h
index 7c2978f173..3513ee2d7d 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -215,6 +215,10 @@
#include "config.h"
#endif
+// Now we need to adjust some settings when running tests
+#ifdef COMPILING_TESTS
+#undef ENABLE_EVENTRECORDER
+#endif
// In the following we configure various targets, in particular those
// which can't use our "configure" tool and hence don't use config.h.
@@ -251,6 +255,7 @@
#if defined(__DC__) || \
defined(__DS__) || \
+ defined(__3DS__) || \
defined(__GP32__) || \
defined(IPHONE) || \
defined(__PLAYSTATION2__) || \
@@ -367,7 +372,7 @@
#endif
#ifndef STRINGBUFLEN
- #if defined(__N64__) || defined(__DS__)
+ #if defined(__N64__) || defined(__DS__) || defined(__3DS__)
#define STRINGBUFLEN 256
#else
#define STRINGBUFLEN 1024
diff --git a/common/str.cpp b/common/str.cpp
index ae3a965c70..3ff49a90c6 100644
--- a/common/str.cpp
+++ b/common/str.cpp
@@ -75,7 +75,7 @@ void String::initWithCStr(const char *str, uint32 len) {
}
String::String(const String &str)
- : _size(str._size) {
+ : _size(str._size) {
if (str.isStorageIntern()) {
// String in internal storage: just copy it
memcpy(_storage, str._storage, _builtinCapacity);
@@ -91,7 +91,7 @@ String::String(const String &str)
}
String::String(char c)
- : _size(0), _str(_storage) {
+ : _size(0), _str(_storage) {
_storage[0] = c;
_storage[1] = 0;
@@ -132,24 +132,19 @@ void String::ensureCapacity(uint32 new_size, bool keep_old) {
if (!isShared && new_size < curCapacity)
return;
- if (isShared && new_size < _builtinCapacity) {
- // We share the storage, but there is enough internal storage: Use that.
- newStorage = _storage;
- newCapacity = _builtinCapacity;
- } else {
- // We need to allocate storage on the heap!
-
- // Compute a suitable new capacity limit
- // If the current capacity is sufficient we use the same capacity
- if (new_size < curCapacity)
- newCapacity = curCapacity;
- else
- newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
-
- // Allocate new storage
- newStorage = new char[newCapacity];
- assert(newStorage);
- }
+ // We need to allocate storage on the heap!
+
+ // Compute a suitable new capacity limit
+ // If the current capacity is sufficient we use the same capacity
+ if (new_size < curCapacity)
+ newCapacity = curCapacity;
+ else
+ newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
+
+ // Allocate new storage
+ newStorage = new char[newCapacity];
+ assert(newStorage);
+
// Copy old data if needed, elsewise reset the new storage.
if (keep_old) {
@@ -444,6 +439,58 @@ uint String::hash() const {
return hashit(c_str());
}
+void String::replace(uint32 pos, uint32 count, const String &str) {
+ replace(pos, count, str, 0, str._size);
+}
+
+void String::replace(uint32 pos, uint32 count, const char *str) {
+ replace(pos, count, str, 0, strlen(str));
+}
+
+void String::replace(iterator begin_, iterator end_, const String &str) {
+ replace(begin_ - _str, end_ - begin_, str._str, 0, str._size);
+}
+
+void String::replace(iterator begin_, iterator end_, const char *str) {
+ replace(begin_ - _str, end_ - begin_, str, 0, strlen(str));
+}
+
+void String::replace(uint32 posOri, uint32 countOri, const String &str,
+ uint32 posDest, uint32 countDest) {
+ replace(posOri, countOri, str._str, posDest, countDest);
+}
+
+void String::replace(uint32 posOri, uint32 countOri, const char *str,
+ uint32 posDest, uint32 countDest) {
+
+ ensureCapacity(_size + countDest - countOri, true);
+
+ // Prepare string for the replaced text.
+ if (countOri < countDest) {
+ uint32 offset = countDest - countOri; ///< Offset to copy the characters
+ uint32 newSize = _size + offset;
+ _size = newSize;
+
+ // Push the old characters to the end of the string
+ for (uint32 i = _size; i >= posOri + countDest; i--)
+ _str[i] = _str[i - offset];
+
+ } else if (countOri > countDest){
+ uint32 offset = countOri - countDest; ///< Number of positions that we have to pull back
+
+ // Pull the remainder string back
+ for (uint32 i = posOri + countDest; i < _size; i++)
+ _str[i] = _str[i + offset];
+
+ _size -= offset;
+ }
+
+ // Copy the replaced part of the string
+ for (uint32 i = 0; i < countDest; i++)
+ _str[posOri + i] = str[posDest + i];
+
+}
+
// static
String String::format(const char *fmt, ...) {
String output;
diff --git a/common/str.h b/common/str.h
index 1b41c481c7..9ada8aaaa0 100644
--- a/common/str.h
+++ b/common/str.h
@@ -46,6 +46,17 @@ namespace Common {
class String {
public:
static const uint32 npos = 0xFFFFFFFF;
+
+ typedef char value_type;
+ /**
+ * Unsigned version of the underlying type. This can be used to cast
+ * individual string characters to bigger integer types without sign
+ * extension happening.
+ */
+ typedef unsigned char unsigned_type;
+ typedef char * iterator;
+ typedef const char * const_iterator;
+
protected:
/**
* The size of the internal storage. Increasing this means less heap
@@ -222,6 +233,38 @@ public:
void trim();
uint hash() const;
+
+ /**@{
+ * Functions to replace some amount of chars with chars from some other string.
+ *
+ * @note The implementation follows that of the STL's std::string:
+ * http://www.cplusplus.com/reference/string/string/replace/
+ *
+ * @param pos Starting position for the replace in the original string.
+ * @param count Number of chars to replace from the original string.
+ * @param str Source of the new chars.
+ * @param posOri Same as pos
+ * @param countOri Same as count
+ * @param posDest Initial position to read str from.
+ * @param countDest Number of chars to read from str. npos by default.
+ */
+ // Replace 'count' bytes, starting from 'pos' with str.
+ void replace(uint32 pos, uint32 count, const String &str);
+ // The same as above, but accepts a C-like array of characters.
+ void replace(uint32 pos, uint32 count, const char *str);
+ // Replace the characters in [begin, end) with str._str.
+ void replace(iterator begin, iterator end, const String &str);
+ // Replace the characters in [begin, end) with str.
+ void replace(iterator begin, iterator end, const char *str);
+ // Replace _str[posOri, posOri + countOri) with
+ // str._str[posDest, posDest + countDest)
+ void replace(uint32 posOri, uint32 countOri, const String &str,
+ uint32 posDest, uint32 countDest);
+ // Replace _str[posOri, posOri + countOri) with
+ // str[posDest, posDest + countDest)
+ void replace(uint32 posOri, uint32 countOri, const char *str,
+ uint32 posDest, uint32 countDest);
+ /**@}*/
/**
* Print formatted data into a String object. Similar to sprintf,
@@ -238,15 +281,6 @@ public:
static String vformat(const char *fmt, va_list args);
public:
- typedef char value_type;
- /**
- * Unsigned version of the underlying type. This can be used to cast
- * individual string characters to bigger integer types without sign
- * extension happening.
- */
- typedef unsigned char unsigned_type;
- typedef char * iterator;
- typedef const char * const_iterator;
iterator begin() {
// Since the user could potentially
diff --git a/common/updates.cpp b/common/updates.cpp
new file mode 100644
index 0000000000..087002a7d3
--- /dev/null
+++ b/common/updates.cpp
@@ -0,0 +1,68 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/updates.h"
+#include "common/translation.h"
+
+namespace Common {
+
+static const int updateIntervals[] = {
+ UpdateManager::kUpdateIntervalNotSupported,
+ UpdateManager::kUpdateIntervalOneDay,
+ UpdateManager::kUpdateIntervalOneWeek,
+ UpdateManager::kUpdateIntervalOneMonth,
+ -1
+};
+
+const int *UpdateManager::getUpdateIntervals() {
+ return updateIntervals;
+}
+
+int UpdateManager::normalizeInterval(int interval) {
+ const int *val = updateIntervals;
+
+ while (*val != -1) {
+ if (*val >= interval)
+ return *val;
+ val++;
+ }
+
+ return val[-1]; // Return maximal acceptable value
+}
+
+const char *UpdateManager::updateIntervalToString(int interval) {
+ switch (interval) {
+ case kUpdateIntervalNotSupported:
+ return _("Never");
+ case kUpdateIntervalOneDay:
+ return _("Daily");
+ case kUpdateIntervalOneWeek:
+ return _("Weekly");
+ case kUpdateIntervalOneMonth:
+ return _("Monthly");
+ default:
+ return _("<Bad value>");
+ }
+}
+
+} // End of namespace Common
diff --git a/common/updates.h b/common/updates.h
index 4c30987c38..3a3049d4df 100644
--- a/common/updates.h
+++ b/common/updates.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef BACKENDS_UPDATES_ABSTRACT_H
-#define BACKENDS_UPDATES_ABSTRACT_H
+#ifndef COMMON_UPDATES_H
+#define COMMON_UPDATES_H
#if defined(USE_UPDATES)
@@ -85,18 +85,50 @@ public:
*
* @param interval The interval.
*/
- virtual void setUpdateCheckInterval(UpdateInterval interval) {}
+ virtual void setUpdateCheckInterval(int interval) {}
/**
* Gets the update check interval.
*
* @return the update check interval.
*/
- virtual UpdateInterval getUpdateCheckInterval() { return kUpdateIntervalNotSupported; }
+ virtual int getUpdateCheckInterval() { return kUpdateIntervalNotSupported; }
+
+ /**
+ * Gets last update check time
+ *
+ * @param t TimeDate struct to fill out
+ * @return flag indicating success
+ */
+ virtual bool getLastUpdateCheckTimeAndDate(TimeDate &t) { return false; }
+
+ /**
+ * Returns list of supported uptate intervals.
+ * Ending with '-1' which is not acceptable value.
+ *
+ * @return list of integer values representing update intervals in seconds.
+ */
+ static const int *getUpdateIntervals();
+
+ /**
+ * Returns string representation of a given interval.
+ *
+ * @param interval The interval.
+ * @return pointer to localized string of given interval.
+ */
+ static const char *updateIntervalToString(int interval);
+
+ /**
+ * Rounds up the given interval to acceptable value.
+ *
+ * @param interval The interval.
+ * @return rounded up interval
+ */
+ static int normalizeInterval(int interval);
};
} // End of namespace Common
#endif
-#endif // BACKENDS_UPDATES_ABSTRACT_H
+#endif // COMMON_UPDATES_H
diff --git a/config.guess b/config.guess
index 6c32c8645c..0967f2afa9 100755
--- a/config.guess
+++ b/config.guess
@@ -1,8 +1,8 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2014 Free Software Foundation, Inc.
+# Copyright 1992-2016 Free Software Foundation, Inc.
-timestamp='2014-11-04'
+timestamp='2016-04-02'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ timestamp='2014-11-04'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
#
# Please send patches to <config-patches@gnu.org>.
@@ -50,7 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ /sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || \
+ echo unknown)`
case "${UNAME_MACHINE_ARCH}" in
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
sh3eb) machine=sh-unknown ;;
sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine=${arch}${endian}-unknown
+ ;;
*) machine=${UNAME_MACHINE_ARCH}-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently, or will in the future.
case "${UNAME_MACHINE_ARCH}" in
- arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ELF__
@@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
os=netbsd
;;
esac
+ # Determine ABI tags.
+ case "${UNAME_MACHINE_ARCH}" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+ ;;
+ esac
# The OS release
# Debian GNU/NetBSD machines have a different userland, and
# thus, need a distinct triplet. However, they do not need
@@ -207,13 +221,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
release='-gnu'
;;
*)
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
;;
esac
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}"
+ echo "${machine}-${os}${release}${abi}"
exit ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@@ -223,6 +237,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+ exit ;;
*:ekkoBSD:*:*)
echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
exit ;;
@@ -235,6 +253,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:MirBSD:*:*)
echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
exit ;;
+ *:Sortix:*:*)
+ echo ${UNAME_MACHINE}-unknown-sortix
+ exit ;;
alpha:OSF1:*:*)
case $UNAME_RELEASE in
*4.0)
@@ -251,42 +272,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
case "$ALPHA_CPU_TYPE" in
"EV4 (21064)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"EV4.5 (21064)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"LCA4 (21066/21068)")
- UNAME_MACHINE="alpha" ;;
+ UNAME_MACHINE=alpha ;;
"EV5 (21164)")
- UNAME_MACHINE="alphaev5" ;;
+ UNAME_MACHINE=alphaev5 ;;
"EV5.6 (21164A)")
- UNAME_MACHINE="alphaev56" ;;
+ UNAME_MACHINE=alphaev56 ;;
"EV5.6 (21164PC)")
- UNAME_MACHINE="alphapca56" ;;
+ UNAME_MACHINE=alphapca56 ;;
"EV5.7 (21164PC)")
- UNAME_MACHINE="alphapca57" ;;
+ UNAME_MACHINE=alphapca57 ;;
"EV6 (21264)")
- UNAME_MACHINE="alphaev6" ;;
+ UNAME_MACHINE=alphaev6 ;;
"EV6.7 (21264A)")
- UNAME_MACHINE="alphaev67" ;;
+ UNAME_MACHINE=alphaev67 ;;
"EV6.8CB (21264C)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.8AL (21264B)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.8CX (21264D)")
- UNAME_MACHINE="alphaev68" ;;
+ UNAME_MACHINE=alphaev68 ;;
"EV6.9A (21264/EV69A)")
- UNAME_MACHINE="alphaev69" ;;
+ UNAME_MACHINE=alphaev69 ;;
"EV7 (21364)")
- UNAME_MACHINE="alphaev7" ;;
+ UNAME_MACHINE=alphaev7 ;;
"EV7.9 (21364A)")
- UNAME_MACHINE="alphaev79" ;;
+ UNAME_MACHINE=alphaev79 ;;
esac
# A Pn.n version is a patched version.
# A Vn.n version is a released version.
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
exitcode=$?
trap '' 0
@@ -359,16 +380,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
eval $set_cc_for_build
- SUN_ARCH="i386"
+ SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
- SUN_ARCH="x86_64"
+ SUN_ARCH=x86_64
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -393,7 +414,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
exit ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
case "`/bin/arch`" in
sun3)
echo m68k-sun-sunos${UNAME_RELEASE}
@@ -618,13 +639,13 @@ EOF
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;;
esac
fi
@@ -663,11 +684,11 @@ EOF
exit (0);
}
EOF
- (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ ${HP_ARCH} = "hppa2.0w" ]
+ if [ ${HP_ARCH} = hppa2.0w ]
then
eval $set_cc_for_build
@@ -680,12 +701,12 @@ EOF
# $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
# => hppa64-hp-hpux11.23
- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
grep -q __LP64__
then
- HP_ARCH="hppa2.0w"
+ HP_ARCH=hppa2.0w
else
- HP_ARCH="hppa64"
+ HP_ARCH=hppa64
fi
fi
echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -790,14 +811,14 @@ EOF
echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -879,7 +900,7 @@ EOF
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
@@ -902,7 +923,7 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
- if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
arc:Linux:*:* | arceb:Linux:*:*)
@@ -933,6 +954,9 @@ EOF
crisv32:Linux:*:*)
echo ${UNAME_MACHINE}-axis-linux-${LIBC}
exit ;;
+ e2k:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
frv:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
@@ -945,6 +969,9 @@ EOF
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
+ k1om:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
m32r*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
exit ;;
@@ -1021,7 +1048,7 @@ EOF
echo ${UNAME_MACHINE}-dec-linux-${LIBC}
exit ;;
x86_64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
exit ;;
xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@@ -1100,7 +1127,7 @@ EOF
# uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i586.
# Note: whatever this is, it MUST be the same as what config.sub
- # prints for the "djgpp" host, or else GDB configury will decide that
+ # prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;;
@@ -1249,6 +1276,9 @@ EOF
SX-8R:SUPER-UX:*:*)
echo sx8r-nec-superux${UNAME_RELEASE}
exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux${UNAME_RELEASE}
+ exit ;;
Power*:Rhapsody:*:*)
echo powerpc-apple-rhapsody${UNAME_RELEASE}
exit ;;
@@ -1262,9 +1292,9 @@ EOF
UNAME_PROCESSOR=powerpc
fi
if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
case $UNAME_PROCESSOR in
@@ -1286,7 +1316,7 @@ EOF
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = "x86"; then
+ if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
@@ -1317,7 +1347,7 @@ EOF
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
- if test "$cputype" = "386"; then
+ if test "$cputype" = 386; then
UNAME_MACHINE=i386
else
UNAME_MACHINE="$cputype"
@@ -1359,7 +1389,7 @@ EOF
echo i386-pc-xenix
exit ;;
i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
exit ;;
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
@@ -1370,6 +1400,9 @@ EOF
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
esac
cat >&2 <<EOF
@@ -1379,9 +1412,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
and
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
diff --git a/config.sub b/config.sub
index 7ffe373784..8d39c4ba39 100755
--- a/config.sub
+++ b/config.sub
@@ -1,8 +1,8 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2014 Free Software Foundation, Inc.
+# Copyright 1992-2016 Free Software Foundation, Inc.
-timestamp='2014-12-03'
+timestamp='2016-03-30'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ timestamp='2014-12-03'
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -53,8 +53,7 @@ timestamp='2014-12-03'
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
- $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
Canonicalize a configuration name.
@@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2014 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +116,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
@@ -255,12 +254,13 @@ case $basic_machine in
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
+ | ba \
| be32 | be64 \
| bfin \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
- | epiphany \
- | fido | fr30 | frv \
+ | e2k | epiphany \
+ | fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
@@ -305,7 +305,7 @@ case $basic_machine in
| riscv32 | riscv64 \
| rl78 | rx \
| score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -376,12 +376,13 @@ case $basic_machine in
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
+ | ba-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
- | elxsi-* \
+ | e2k-* | elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@@ -428,12 +429,13 @@ case $basic_machine in
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
+ | riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
@@ -518,6 +520,9 @@ case $basic_machine in
basic_machine=i386-pc
os=-aros
;;
+ asmjs)
+ basic_machine=asmjs-unknown
+ ;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -1373,11 +1378,11 @@ case $os in
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* \
+ | -aos* | -aros* | -cloudabi* | -sortix* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -bitrig* | -openbsd* | -solidbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
@@ -1393,7 +1398,8 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+ | -onefs* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1525,6 +1531,8 @@ case $os in
;;
-nacl*)
;;
+ -ios)
+ ;;
-none)
;;
*)
diff --git a/configure b/configure
index 6bc0e857aa..9e2a19de34 100755
--- a/configure
+++ b/configure
@@ -128,13 +128,13 @@ _timidity=auto
_zlib=auto
_mpeg2=auto
_sparkle=auto
+_osxdockplugin=auto
_jpeg=auto
_png=auto
_theoradec=auto
_faad=auto
_fluidsynth=auto
-_opengl=auto
-_opengles=auto
+_opengl_mode=auto
_readline=auto
_freetype2=auto
_taskbar=auto
@@ -162,6 +162,7 @@ _translation=yes
# Default platform settings
_backend=sdl
_16bit=auto
+_highres=auto
_savegame_timestamp=auto
_dynamic_modules=no
_elf_loader=no
@@ -181,6 +182,8 @@ _stagingpath="staging"
_win32path="c:/scummvm"
_amigaospath="Games:ScummVM"
_staticlibpath=
+_xcodetoolspath=
+_sparklepath=
_sdlconfig=sdl-config
_freetypeconfig=freetype-config
_sdlpath="$PATH"
@@ -201,6 +204,7 @@ add_feature 16bit "16bit color" "_16bit"
add_feature faad "libfaad" "_faad"
add_feature flac "FLAC" "_flac"
add_feature freetype2 "FreeType2" "_freetype2"
+add_feature highres "high resolution" "_highres"
add_feature mad "MAD" "_mad"
add_feature jpeg "JPEG" "_jpeg"
add_feature png "PNG" "_png"
@@ -436,7 +440,7 @@ get_system_exe_extension() {
arm-riscos)
_exeext=",ff8"
;;
- dreamcast | ds | gamecube | n64 | ps2 | psp | wii)
+ 3ds | dreamcast | ds | gamecube | n64 | ps2 | psp | wii)
_exeext=".elf"
;;
gph-linux)
@@ -805,18 +809,6 @@ get_subengines_build_string() {
}
#
-# Greet user
-#
-echo "Running ScummVM configure..."
-echo "Configure run on" `date` > $TMPLOG
-cat >> $TMPLOG <<EOF
-Invocation command line was:
-$0 $@
-Saved environment variables:
-LDFLAGS="$SAVED_LDFLAGS" CXX="$SAVED_CXX" CXXFLAGS="$SAVED_CXXFLAGS" CPPFLAGS="$SAVED_CPPFLAGS" ASFLAGS="$SAVED_ASFLAGS" WINDRESFLAGS="$SAVED_WINDRESFLAGS" SDL_CONFIG="$SAVED_SDL_CONFIG"
-EOF
-
-#
# Check any parameters we received
#
# TODO:
@@ -839,9 +831,9 @@ Usage: $0 [OPTIONS]...
Configuration:
-h, --help display this help and exit
- --backend=BACKEND backend to build (android, tizen, dc, dingux, ds, gcw0,
+ --backend=BACKEND backend to build (3ds, android, dc, dingux, ds, gcw0,
gph, iphone, ios7, linuxmoto, maemo, n64, null, openpandora,
- ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl]
+ ps2, psp, samsungtv, sdl, tizen, webos, wii, wince) [sdl]
Installation directories:
--prefix=PREFIX install architecture-independent files in PREFIX
@@ -867,10 +859,11 @@ Fine tuning of the installation directories:
Special configuration feature:
--host=HOST cross-compile to target HOST (arm-linux, ...)
- special targets: android-arm for Android ARM
+ special targets: 3ds for Nintendo 3DS
+ android-arm for Android ARM
android-mips for Android MIPS
android-x86 for Android x86
- tizen for Samsung Tizen
+ androidsdl for Android with SDL backend
caanoo for Caanoo
dingux for Dingux
raspberrypi for Raspberry Pi
@@ -893,6 +886,7 @@ Special configuration feature:
ps3 for PlayStation 3
psp for PlayStation Portable
samsungtv for Samsung TV
+ tizen for Samsung Tizen
webos for HP Palm WebOS
wii for Nintendo Wii
wince for Windows CE
@@ -922,6 +916,7 @@ Optional Features:
--default-dynamic make plugins dynamic by default
--disable-mt32emu don't enable the integrated MT-32 emulator
--disable-16bit don't enable 16bit color support
+ --disable-highres don't enable support for high resolution engines >320x240
--disable-savegame-timestamp don't use timestamps for blank savegame descriptions
--disable-scalers exclude scalers
--disable-hq-scalers exclude HQ2x and HQ3x scalers
@@ -936,6 +931,15 @@ Optional Features:
--enable-verbose-build enable regular echoing of commands during build
process
--disable-bink don't build with Bink video support
+ --opengl-mode=MODE OpenGL (ES) mode to use for OpenGL output [auto]
+ available modes: auto for autodetection
+ none for disabling any OpenGL usage
+ any for runtime detection
+ gl for forcing OpenGL
+ gles for forcing OpenGL ES
+ gles2 for forcing OpenGL ES 2
+ WARNING: only specify this manually if you know what
+ you are doing!
Optional Libraries:
--with-alsa-prefix=DIR Prefix where alsa is installed (optional)
@@ -960,9 +964,6 @@ Optional Libraries:
--with-mpeg2-prefix=DIR Prefix where libmpeg2 is installed (optional)
--enable-mpeg2 enable mpeg2 codec for cutscenes [autodetect]
- --with-opengl-prefix=DIR Prefix where OpenGL (ES) is installed (optional)
- --disable-opengl disable OpenGL (ES) support [autodetect]
-
--with-jpeg-prefix=DIR Prefix where libjpeg is installed (optional)
--disable-jpeg disable JPEG decoder [autodetect]
@@ -979,8 +980,10 @@ Optional Libraries:
installed (optional)
--disable-fluidsynth disable fluidsynth MIDI driver [autodetect]
- --with-sparkle-prefix=DIR Prefix where sparkle is installed (Mac OS X only - optional)
- --disable-sparkle disable sparkle automatic update support [Mac OS X only - autodetect]
+ --with-sparkle-prefix=DIR Prefix where sparkle is installed (OS X/Windows only - optional)
+ --disable-sparkle disable sparkle automatic update support [OS X/Windows only - autodetect]
+
+ --disable-osx-dock-plugin disable the NSDockTilePlugin support [Mac OS X only - autodetect]
--with-sdl-prefix=DIR Prefix where the sdl-config script is
installed (optional)
@@ -1016,9 +1019,25 @@ EOF
fi
done # for parm in ...
+
+#
+# If we're not showing help, greet the user and start the log file
+#
+echo "Running ScummVM configure..."
+echo "Configure run on" `date` > $TMPLOG
+cat >> $TMPLOG <<EOF
+Invocation command line was:
+$0 $@
+Saved environment variables:
+LDFLAGS="$SAVED_LDFLAGS" CXX="$SAVED_CXX" CXXFLAGS="$SAVED_CXXFLAGS" CPPFLAGS="$SAVED_CPPFLAGS" ASFLAGS="$SAVED_ASFLAGS" WINDRESFLAGS="$SAVED_WINDRESFLAGS" SDL_CONFIG="$SAVED_SDL_CONFIG"
+EOF
+
+
for ac_option in $@; do
case "$ac_option" in
--disable-16bit) _16bit=no ;;
+ --enable-highres) _highres=yes ;;
+ --disable-highres) _highres=no ;;
--disable-savegame-timestamp) _savegame_timestamp=no ;;
--disable-scalers) _build_scalers=no ;;
--disable-hq-scalers) _build_hq_scalers=no ;;
@@ -1042,6 +1061,8 @@ for ac_option in $@; do
--disable-zlib) _zlib=no ;;
--enable-sparkle) _sparkle=yes ;;
--disable-sparkle) _sparkle=no ;;
+ --enable-osx-dock-plugin) _osxdockplugin=yes;;
+ --disable-osx-dock-plugin) _osxdockplugin=no;;
--enable-nasm) _nasm=yes ;;
--disable-nasm) _nasm=no ;;
--enable-mpeg2) _mpeg2=yes ;;
@@ -1065,10 +1086,11 @@ for ac_option in $@; do
--disable-updates) _updates=no ;;
--enable-libunity) _libunity=yes ;;
--disable-libunity) _libunity=no ;;
- --enable-opengl) _opengl=yes ;;
- --disable-opengl) _opengl=no ;;
--enable-bink) _bink=yes ;;
--disable-bink) _bink=no ;;
+ --opengl-mode=*)
+ _opengl_mode=`echo $ac_option | cut -d '=' -f 2`
+ ;;
--enable-verbose-build) _verbose_build=yes ;;
--enable-plugins) _dynamic_modules=yes ;;
--default-dynamic) _plugins_default=dynamic ;;
@@ -1156,8 +1178,7 @@ for ac_option in $@; do
;;
--with-sparkle-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
- SPARKLE_CFLAGS="-F$arg"
- SPARKLE_LIBS="-F$arg"
+ _sparklepath=$arg
;;
--with-readline-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
@@ -1169,11 +1190,6 @@ for ac_option in $@; do
LIBUNITY_CFLAGS="-I$arg/include"
LIBUNITY_LIBS="-L$arg/lib"
;;
- --with-opengl-prefix=*)
- arg=`echo $ac_option | cut -d '=' -f 2`
- OPENGL_CFLAGS="-I$arg/include"
- OPENGL_LIBS="-L$arg/lib"
- ;;
--backend=*)
_backend=`echo $ac_option | cut -d '=' -f 2`
;;
@@ -1230,6 +1246,9 @@ for ac_option in $@; do
--with-staticlib-prefix=*)
_staticlibpath=`echo $ac_option | cut -d '=' -f 2`
;;
+ --with-xcodetools-path=*)
+ _xcodetoolspath=`echo $ac_option | cut -d '=' -f 2`
+ ;;
--host=*)
_host=`echo $ac_option | cut -d '=' -f 2`
;;
@@ -1294,6 +1313,11 @@ get_system_exe_extension $guessed_host
NATIVEEXEEXT=$_exeext
case $_host in
+3ds)
+ _host_os=3ds
+ _host_cpu=arm
+ _host_alias=arm-none-eabi
+ ;;
android | android-arm | android-v7a | android-arm-v7a | ouya)
_host_os=android
_host_cpu=arm
@@ -1309,6 +1333,26 @@ android-x86)
_host_cpu=i686
_host_alias=i686-linux-android
;;
+androidsdl-armeabi | androidsdl-armeabi-v7a)
+ _host_os=androidsdl
+ _host_cpu=arm
+ _host_alias=arm-linux-androideabi
+ ;;
+androidsdl-arm64-v8a)
+ _host_os=androidsdl
+ _host_cpu=aarch64
+ _host_alias=aarch64-linux-android
+ ;;
+androidsdl-mips)
+ _host_os=androidsdl
+ _host_cpu=mipsel
+ _host_alias=mipsel-linux-android
+ ;;
+androidsdl-x86)
+ _host_os=androidsdl
+ _host_cpu=i686
+ _host_alias=i686-linux-android
+ ;;
arm-riscos)
_host_os=riscos
_host_cpu=arm
@@ -1575,7 +1619,7 @@ android)
exit 1
fi
;;
-ds | gamecube | wii)
+3ds | ds | gamecube | wii)
if test -z "$DEVKITPRO"; then
echo "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to devkitPRO>"
exit 1
@@ -1831,7 +1875,7 @@ if test "$have_gcc" = yes ; then
case $_host_os in
# newlib-based system include files suppress non-C89 function
# declarations under __STRICT_ANSI__
- amigaos* | android | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
+ 3ds | amigaos* | android | androidsdl | dreamcast | ds | gamecube | mingw* | n64 | psp | ps2 | ps3 | tizen | wii | wince )
;;
*)
append_var CXXFLAGS "-ansi"
@@ -1867,7 +1911,7 @@ echo $_use_cxx11
# However, some platforms use GNU extensions in system header files, so
# for these we must not use -pedantic.
case $_host_os in
-android | gamecube | psp | tizen | wii | webos)
+android | androidsdl | gamecube | psp | tizen | wii | webos)
;;
*)
# ICC does not support pedantic, while GCC and clang do.
@@ -2131,6 +2175,27 @@ esac
echo_n "Checking hosttype... "
echo $_host_os
case $_host_os in
+ 3ds)
+ _optimization_level=-O2
+ append_var DEFINES "-D__3DS__"
+ append_var DEFINES "-DARM"
+ append_var DEFINES "-DARM11"
+ append_var CXXFLAGS "-march=armv6k"
+ append_var CXXFLAGS "-mtune=mpcore"
+ append_var CXXFLAGS "-mword-relocations"
+ append_var CXXFLAGS "-mfloat-abi=hard"
+ append_var CXXFLAGS "-ffunction-sections"
+ append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var CXXFLAGS "-I$DEVKITPRO/libctru/include"
+ append_var CXXFLAGS "-I$DEVKITPRO/portlibs/3ds/include"
+ if test "$_dynamic_modules" = no ; then
+ append_var LDFLAGS "-Wl,--gc-sections"
+ else
+ append_var LDFLAGS "-Wl,--no-gc-sections"
+ fi
+ append_var LDFLAGS "-L$DEVKITPRO/portlibs/3ds/lib"
+ append_var LIBS "-lcitro3d -lctru"
+ ;;
amigaos*)
append_var LDFLAGS "-Wl,--export-dynamic"
append_var LDFLAGS "-L/sdk/local/newlib/lib"
@@ -2345,6 +2410,17 @@ case $_host_os in
echo "Could not determine prefix for static libraries"
fi
fi
+
+ # If _xcodetoolspath is not set yet use xcode-select to get the path
+ if test -z "$_xcodetoolspath"; then
+ _xcodetoolspath=`xcode-select -print-path`/Tools
+ if test -d "$_xcodetoolspath"; then
+ echo "Set xcodetools-path to ${_xcodetoolspath}"
+ else
+ _xcodetoolspath=
+ echo "Could not determine path for Xcode Tools"
+ fi
+ fi
;;
dreamcast)
append_var DEFINES "-D__DC__"
@@ -2438,6 +2514,10 @@ case $_host_os in
mint*)
append_var DEFINES "-DSYSTEM_NOT_SUPPORTING_D_TYPE"
;;
+ msys)
+ echo ERROR: Using the MSYS shell in msys mode is not supported. Please use the MSYS shell in mingw mode instead.
+ exit 1
+ ;;
n64)
append_var DEFINES "-D__N64__"
append_var DEFINES "-DLIMIT_FPS"
@@ -2553,6 +2633,18 @@ if test -n "$_host"; then
# Cross-compiling mode - add your target here if needed
echo "Cross-compiling to $_host"
case "$_host" in
+ 3ds)
+ append_var DEFINES "-DDISABLE_FANCY_THEMES"
+ append_var DEFINES "-DDISABLE_SID"
+ append_var DEFINES "-DDISABLE_NES_APU"
+ _backend="3ds"
+ _build_scalers=no
+ _vkeybd=yes
+ _mt32emu=no
+ # Should use Tremor instead of Vorbis
+ _vorbis=no
+ _port_mk="backends/platform/3ds/3ds.mk"
+ ;;
android | android-arm | android-v7a | android-arm-v7a | android-mips | android-x86 | ouya)
# we link a .so as default
append_var LDFLAGS "-shared"
@@ -2566,6 +2658,15 @@ if test -n "$_host"; then
_mt32emu=no
_timidity=no
;;
+ androidsdl | androidsdl-armeabi | androidsdl-armeabi-v7a | androidsdl-mips | androidsdl-x86 | androidsdl-arm64-v8a)
+ DEFINES="$DEFINES -DANDROIDSDL"
+ _unix=yes
+ _seq_midi=no
+ _mt32emu=no
+ _timidity=no
+ _backend="androidsdl"
+ _port_mk="backends/platform/androidsdl/androidsdl.mk"
+ ;;
arm-linux|arm*-linux-gnueabi|arm-*-linux)
;;
arm-riscos|linupy)
@@ -2635,10 +2736,11 @@ if test -n "$_host"; then
# since SDL2 manages dispmanx/GLES2 very well internally.
# SDL1 is bit-rotten on this platform.
_sdlconfig=sdl2-config
- # OpenGL(ES) support is mature enough as to be the best option on
+ # OpenGL ES support is mature enough as to be the best option on
# the Raspberry Pi, so it's enabled by default.
- _opengl=yes
- _opengles=yes
+ # The Raspberry Pi always supports OpenGL ES 2.0 contexts, thus we
+ # take advantage of those.
+ _opengl_mode=gles2
;;
dreamcast)
append_var DEFINES "-DDISABLE_DEFAULT_SAVEFILEMANAGER"
@@ -2699,21 +2801,19 @@ if test -n "$_host"; then
gcw0)
_sysroot=`$CXX --print-sysroot`
_sdlpath=$_sysroot/usr/bin
- append_var DEFINES "-DDINGUX -DGCW0"
+ append_var DEFINES "-DDINGUX -DGCW0 -DGUI_ONLY_FULLSCREEN"
append_var DEFINES "-DREDUCE_MEMORY_USAGE"
append_var CXXFLAGS "-mips32"
_backend="dingux"
+ _alsa=no
_mt32emu=no
+ _seq_midi=no
+ _timidity=no
+ _build_scalers=no
_optimization_level=-O3
- # Disable alsa midi to get the port build on OpenDingux toolchain
- _alsa=no
_vkeybd=yes
- _build_hq_scalers=no
_keymapper=yes
- # Force disable vorbis on dingux, it has terrible performance compared to tremor
_vorbis=no
- # Force disable seq on dingux, no way to use it and it would get enabled by default with configure
- _seq_midi=no
_port_mk="backends/platform/dingux/dingux.mk"
;;
gp2x)
@@ -2966,6 +3066,8 @@ if test -n "$_host"; then
_mt32emu=no
_timidity=no
_vkeybd=yes
+ # Tizen relies on the OpenGL ES output thus we always enable it.
+ _opengl_mode=gles
;;
webos)
_backend="webos"
@@ -3011,12 +3113,16 @@ fi
# Backend related stuff
#
case $_backend in
+ 3ds)
+ ;;
android)
append_var DEFINES "-DREDUCE_MEMORY_USAGE"
append_var CXXFLAGS "-Wa,--noexecstack"
append_var LDFLAGS "-Wl,-z,noexecstack"
append_var INCLUDES "-I$ANDROID_NDK/sources/cxx-stl/system/include"
;;
+ androidsdl)
+ ;;
dc)
append_var INCLUDES '-I$(srcdir)/backends/platform/dc'
append_var INCLUDES '-isystem $(ronindir)/include'
@@ -3113,6 +3219,8 @@ case $_backend in
append_var LDFLAGS "-shared"
append_var LDFLAGS "-fpic"
;;
+ sdl)
+ ;;
tizen)
# dirent.h not available. NONSTANDARD_PORT==ensure portdefs.h is included
append_var DEFINES "-DTIZEN -DDISABLE_STDIO_FILESTREAM -DNONSTANDARD_PORT"
@@ -3161,8 +3269,6 @@ case $_backend in
append_var DEFINES "-DSDL_BACKEND"
add_line_to_config_mk "SDL_BACKEND = 1"
;;
- sdl)
- ;;
*)
echo "support for $_backend backend not implemented in configure script yet"
exit 1
@@ -3174,7 +3280,7 @@ append_var MODULES "backends/platform/$_backend"
# Setup SDL specifics for SDL based backends
#
case $_backend in
- dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl)
+ androidsdl | dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl)
find_sdlconfig
append_var INCLUDES "`$_sdlconfig --prefix="$_sdlpath" --cflags`"
append_var LIBS "`$_sdlconfig --prefix="$_sdlpath" --libs`"
@@ -3197,7 +3303,7 @@ esac
# Enable 16bit support only for backends which support it
#
case $_backend in
- android | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii)
+ 3ds | android | androidsdl | dingux | dc | gph | iphone | ios7 | maemo | openpandora | psp | samsungtv | sdl | tizen | webos | wii)
if test "$_16bit" = auto ; then
_16bit=yes
else
@@ -3210,6 +3316,26 @@ case $_backend in
esac
#
+# Enable High resolution engines (>320x240) support only for backends which support it
+#
+case $_host in
+ gcw0)
+ if test "$_highres" = yes ; then
+ _highres=yes
+ else
+ _highres=no
+ fi
+ ;;
+ *)
+ if test "$_highres" = no ; then
+ _highres=no
+ else
+ _highres=yes
+ fi
+ ;;
+esac
+
+#
# Enable Event Recorder only for backends that support it
#
case $_backend in
@@ -3256,7 +3382,7 @@ case $_host_os in
amigaos* | cygwin* | dreamcast | ds | gamecube | mingw* | n64 | ps2 | ps3 | psp | wii | wince)
_posix=no
;;
- android | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos)
+ 3ds | android | androidsdl | beos* | bsd* | darwin* | freebsd* | gnu* | gph-linux | haiku* | hpux* | iphone | ios7 | irix*| k*bsd*-gnu* | linux* | maemo | mint* | netbsd* | openbsd* | solaris* | sunos* | uclinux* | webos)
_posix=yes
;;
os2-emx*)
@@ -3522,6 +3648,11 @@ define_in_config_if_yes "$_mt32emu" 'USE_MT32EMU'
define_in_config_if_yes "$_16bit" 'USE_RGB_COLOR'
#
+# Check whether High resolution graphics support is requested
+#
+define_in_config_if_yes "$_highres" 'USE_HIGHRES'
+
+#
# Check whether save games use the current time as default description
#
define_in_config_if_yes "$_savegame_timestamp" 'USE_SAVEGAME_TIMESTAMP'
@@ -3879,26 +4010,90 @@ echo "$_mpeg2"
#
# Check for Sparkle if updates support is enabled
#
-echocheck "Sparkle"
-if test "$_updates" = no; then
- _sparkle=no
-else
-if test "$_sparkle" = auto ; then
- _sparkle=no
- cat > $TMPC << EOF
+#
+# Check is NSDockTilePlugIn protocol is supported
+#
+case $_host_os in
+ darwin*)
+ echocheck "Sparkle"
+ if test "$_updates" = no; then
+ _sparkle=no
+ else
+ if test ! -z $_sparklepath ; then
+ SPARKLE_CFLAGS="-F$_sparklepath"
+ SPARKLE_LIBS="-F$_sparklepath"
+ fi
+ if test "$_sparkle" = auto ; then
+ _sparkle=no
+ cat > $TMPC << EOF
#include <Cocoa/Cocoa.h>
#include <Sparkle/Sparkle.h>
int main(void) { SUUpdater *updater = [SUUpdater sharedUpdater]; return 0; }
EOF
- cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -framework Sparkle -ObjC++ -lobjc && _sparkle=yes
-fi
-if test "$_sparkle" = yes ; then
- append_var LIBS "$SPARKLE_LIBS -framework Sparkle"
- append_var INCLUDES "$SPARKLE_CFLAGS"
-fi
-define_in_config_if_yes "$_sparkle" 'USE_SPARKLE'
-fi
-echo "$_sparkle"
+ cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -framework Sparkle -ObjC++ -lobjc && _sparkle=yes
+ fi
+ if test "$_sparkle" = yes ; then
+ append_var LIBS "$SPARKLE_LIBS -framework Sparkle"
+ append_var INCLUDES "$SPARKLE_CFLAGS"
+ fi
+ define_in_config_if_yes "$_sparkle" 'USE_SPARKLE'
+ fi
+ echo "$_sparkle"
+ ;;
+ mingw*)
+ echocheck "Sparkle"
+ if test "$_updates" = no; then
+ _sparkle=no
+ else
+ if test ! -z $_sparklepath ; then
+ SPARKLE_CFLAGS="-I$_sparklepath/include"
+ SPARKLE_LIBS="-L$_sparklepath/Release -L$_sparklepath/x64/Release"
+ fi
+ if test "$_sparkle" = auto ; then
+ _sparkle=no
+ cat > $TMPC << EOF
+#include <winsparkle.h>
+int main(void) { win_sparkle_get_update_check_interval(); return 0; }
+EOF
+ cc_check $SPARKLE_CFLAGS $SPARKLE_LIBS -lWinSparkle && _sparkle=yes
+ fi
+ if test "$_sparkle" = yes ; then
+ append_var LIBS "$SPARKLE_LIBS -lWinSparkle"
+ append_var INCLUDES "$SPARKLE_CFLAGS"
+ fi
+ define_in_config_if_yes "$_sparkle" 'USE_SPARKLE'
+ fi
+ echo "$_sparkle"
+ ;;
+ *)
+ _sparkle=no
+ ;;
+esac
+
+#
+# Check is NSDockTilePlugIn protocol is supported
+#
+case $_host_os in
+ darwin*)
+ # NSDockTilePlugIn was added in OS X 10.6, so will not be available when compiling on older OS X versions.
+ echocheck "DockTilePlugin"
+ if test "$_osxdockplugin" = auto ; then
+ _osxdockplugin=no
+ cat > $TMPC << EOF
+#include <Cocoa/Cocoa.h>
+@interface ScummVMDockTilePlugIn : NSObject <NSDockTilePlugIn> {
+}
+@end
+EOF
+ cc_check -c -ObjC++ && _osxdockplugin=yes
+ fi
+ define_in_config_if_yes "$_osxdockplugin" 'USE_DOCKTILEPLUGIN'
+ echo "$_osxdockplugin"
+ ;;
+ *)
+ _osxdockplugin=no
+ ;;
+esac
#
# Check for FluidSynth
@@ -3908,10 +4103,7 @@ echocheck "FluidSynth"
append_var FLUIDSYNTH_LIBS "-lfluidsynth"
case $_host_os in
mingw*)
- # NOTE: Windows builds use an older FluidSynth version (1.0.9)
- # which doesn't require glib, to avoid bundling the complete glib
- # libraries with Windows builds.
- FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -ldsound -lwinmm"
+ FLUIDSYNTH_STATIC_LIBS="$FLUIDSYNTH_LIBS -lglib-2.0 -lintl -liconv -lws2_32 -lole32 -lshlwapi -lpcre -ldsound -lwinmm"
;;
darwin*)
@@ -4104,113 +4296,115 @@ echocheck "OpenGL"
case $_backend in
openpandora)
- # Only enable OpenGL ES on the OpanPandora if --enable-opengl is passed in explicitly.
- if test "$_opengl" = yes ; then
- _opengl=yes
- _opengles=yes
- OPENGL_LIBS="-lGLES_CM -lEGL -lX11"
- OPENGL_CFLAGS="$OPENGL_LIBS"
- append_var LIBS "$OPENGL_LIBS"
- append_var INCLUDES "$OPENGL_CFLAGS"
+ # Only enable OpenGL ES on the OpanPandora if --opengl-mode=gles is passed in explicitly.
+ if test "$_opengl_mode" = "gles" ; then
+ append_var LIBS "-lGLES_CM -lEGL -lX11"
+ else
+ _opengl_mode=none
fi
;;
esac
-if test "$_opengl" = auto ; then
- _opengl=no
- if test "$_backend" = "sdl" ; then
- # Try different header filenames
- # 1) GL/gl.h This is usually used on POSIX and Windows systems
- # 2) OpenGL/gl.h This is used on Mac OS X
- # 3) GLES/gl.h This is used for OpenGL ES 1.x
- for i in "GL/gl.h" "OpenGL/gl.h" "GLES/gl.h"; do
- # Test the current header for OpenGL
- cat > $TMPC << EOF
-#include <$i>
-#include <stdio.h>
-int main(void) { printf("ANTIVIRUS FALSE POSITIVE WORKAROUND"); return GL_VERSION_1_1; }
-EOF
- cc_check $DEFINES $OPENGL_CFLAGS $OPENGL_LIBS && _opengl=yes && break
+if test "$_opengl_mode" = auto ; then
+ case $_backend in
+ sdl)
+ case $_sdlversion in
+ 1.2.*)
+ # Stock SDL 1.2 only supports OpenGL contexts.
+ _opengl_mode=gl
+ ;;
- # Test the current header for OpenGL ES
- cat > $TMPC << EOF
-#include <$i>
-int main(void) { return GL_OES_VERSION_1_1; }
-EOF
- cc_check $DEFINES $OPENGL_CFLAGS $OPENGL_LIBS && _opengl=yes && _opengles=yes && break
+ 2.0.*)
+ # SDL2 supports both OpenGL + OpenGL ES contexts.
+ # However, Mac OS X only allows OpenGL context creation at
+ # this time, thus we limit us to OpenGL on that platform.
+ case $_host_os in
+ darwin*)
+ _opengl_mode=gl
+ ;;
+
+ *)
+ _opengl_mode=any
+ ;;
+ esac
+ ;;
+ esac
+ ;;
- # Test the current header for OpenGL ES on SBCs (Raspberry Pi, Cubieboard, etc)
- cat > $TMPC << EOF
-#include <$i>
-int main(void) { return GL_VERSION_ES_CM_1_1; }
-EOF
- cc_check $DEFINES $OPENGL_CFLAGS $OPENGL_LIBS && _opengl=yes && _opengles=yes && break
- done
- fi
+ tizen)
+ # Tizen always runs in GLES mode
+ _opengl_mode=gles
+ ;;
+
+ *)
+ _opengl_mode=none
+ ;;
+ esac
fi
-if test "$_opengl" = yes ; then
- # Our simple test case
- cat > $TMPC << EOF
-int main(void) { return 0; }
-EOF
- _opengl=no
- # Try different library names
- if test "$_opengles" = "yes" ; then
- # 1) GLES_CM This is usually used for OpenGL ES 1.1 (Common profile)
- # 2) GLESv1_CM This is used by the Windows Mali OpenGL ES 1.1 Emulator
- # 3) glesv1 This is used by the Linux Mali OpenGL ES 1.1 Emulator
- _opengles=no
- for lib in "-lGLES_CM" "-lGLESv1_CM" "-lglesv1"; do
- if cc_check_no_clean $DEFINES $OPENGL_CFLAGS $OPENGL_LIBS $lib
- then
- _opengl=yes
- _opengles=yes
- OPENGL_LIBS="$OPENGL_LIBS $lib"
- break
- fi
- done
- else
- # 1) -framework OpenGL This is used on Mac OS X
- # 2) GL This is usually used on POSIX systems
- # 3) opengl32 This is used on Windows
- #
- # We try "-framework OpenGL" first here to assure it will always be
- # picked up by the configure script on Mac OS X, even when a libGL
- # exists.
- for lib in "-framework OpenGL" "-lGL" "-lopengl32"; do
- if cc_check_no_clean $DEFINES $OPENGL_CFLAGS $OPENGL_LIBS $lib
- then
- _opengl=yes
- OPENGL_LIBS="$OPENGL_LIBS $lib"
- break
- fi
- done
- fi
- cc_check_clean
+_opengl=yes
+case $_opengl_mode in
+ auto)
+ # This case should never occur but better safe than sorry.
+ echo "no"
+ _opengl=no
+ ;;
- if test "$_opengl" = yes ; then
- append_var LIBS "$OPENGL_LIBS"
- append_var INCLUDES "$OPENGL_CFLAGS"
- fi
-fi
+ none)
+ echo "no"
+ _opengl=no
+ ;;
-case $_host_os in
- tizen)
- # components live in non-standard locations so just assume sane SDK
- _opengl=yes
- _opengles=yes
+ any)
+ echo "yes (runtime detection)"
+ add_line_to_config_h "#undef USE_GLES_MODE"
;;
-esac
-if test "$_opengles" = "yes" ; then
- echo "yes (OpenGL ES)"
-else
- echo "$_opengl"
-fi
+ gl)
+ echo "yes (OpenGL)"
+ add_line_to_config_h "#define USE_GLES_MODE 0"
+ ;;
+
+ gles)
+ echo "yes (OpenGL ES)"
+ add_line_to_config_h "#define USE_GLES_MODE 1"
+ ;;
+
+ gles2)
+ echo "yes (OpenGL ES 2)"
+ add_line_to_config_h "#define USE_GLES_MODE 2"
+ ;;
+
+ *)
+ echo "invalid mode specification '$_opengl_mode'. Aborting."
+ exit 1
+ ;;
+esac
define_in_config_if_yes "$_opengl" "USE_OPENGL"
-define_in_config_if_yes "$_opengles" "USE_GLES"
+
+#
+# Check for Linux CD-ROM support
+#
+case $_host_os in
+ *linux*)
+ echocheck "Linux CD-ROM"
+ linuxcd=no
+ cat > $TMPC << EOF
+#include <linux/cdrom.h>
+#include <sys/types.h>
+int main(void) {
+ int x = CDROMREADAUDIO;
+ dev_t dev;
+ return major(dev) + x;
+}
+EOF
+ cc_check && linuxcd=yes
+ define_in_config_if_yes "$linuxcd" 'USE_LINUXCD'
+ echo "$linuxcd"
+ ;;
+esac
+
#
# Check for nasm
@@ -4424,6 +4618,10 @@ if test "$_16bit" = yes ; then
echo_n ", 16bit color"
fi
+if test "$_highres" = yes ; then
+ echo_n ", high resolution"
+fi
+
if test "$_savegame_timestamp" = yes ; then
echo_n ", savegame timestamp"
fi
@@ -4437,7 +4635,7 @@ if test "$_build_scalers" = yes ; then
fi
if test "$_mt32emu" = yes ; then
- echo_n ", MT-32 emu"
+ echo_n ", MT-32 emulator"
fi
if test "$_text_console" = yes ; then
@@ -4463,6 +4661,14 @@ fi
# after all of CXXFLAGS, LDFLAGS, LIBS etc. have been setup
#
case $_backend in
+ 3ds)
+ if test "$_freetype2" = yes -a "$_png" = yes; then
+ append_var LIBS "-lpng"
+ fi
+ if test "$_tremor" = yes -o "$_flac" = yes; then
+ append_var LIBS "-logg"
+ fi
+ ;;
android)
# ssp at this point so the cxxtests link
if test "$_debug_build" = yes; then
@@ -4694,6 +4900,8 @@ STAGINGPATH=$_stagingpath
WIN32PATH=$_win32path
AMIGAOSPATH=$_amigaospath
STATICLIBPATH=$_staticlibpath
+XCODETOOLSPATH=$_xcodetoolspath
+SPARKLEPATH=$_sparklepath
SDLCONFIG=$_sdlconfig
ABI := $ABI
diff --git a/devtools/create_wage/create_wage.sh b/devtools/create_classicmacfonts.sh
index 5e8fe352a2..517f3f5638 100755
--- a/devtools/create_wage/create_wage.sh
+++ b/devtools/create_classicmacfonts.sh
@@ -4,7 +4,7 @@
# from it. Mac only, unfortunately.
#
# On Windows you perhaps can perform the extraction manually with use of
-# HFV Explorer: https://web.archive.org/web/20011202005455/http://gamma.nic.fi/~lpesonen/HFVExplorer/
+# HFSxplorer: http://www.catacombae.org/hfsexplorer/
#
# More information could be found in the vMac documentation: http://www.gryphel.com/c/image/
#
@@ -106,8 +106,8 @@ echo_n "Converting fonts..."
fondu-060102/fondu -force *.bin
echo done
-zip -9 wage *.bdf
-mv wage.zip wage.dat
+zip -9 classicmacfonts *.bdf
+mv classicmacfonts.zip classicmacfonts.dat
echo_n "Cleaning up..."
rm *.bdf
@@ -116,4 +116,4 @@ rm *.bin
rm *.dmg
echo done
-ls -l wage.dat
+ls -l classicmacfonts.dat
diff --git a/devtools/create_kyradat/create_kyradat.cpp b/devtools/create_kyradat/create_kyradat.cpp
index e064e899de..294eadf92b 100644
--- a/devtools/create_kyradat/create_kyradat.cpp
+++ b/devtools/create_kyradat/create_kyradat.cpp
@@ -45,7 +45,7 @@
enum {
- kKyraDatVersion = 87
+ kKyraDatVersion = 88
};
const ExtractFilename extractFilenames[] = {
@@ -119,7 +119,6 @@ const ExtractFilename extractFilenames[] = {
// AUDIO filename table
{ k1AudioTracks, kStringList, false },
- { k1AudioTracks2, kStringList, false },
{ k1AudioTracksIntro, kStringList, false },
// AMULET anim
diff --git a/devtools/create_kyradat/create_kyradat.h b/devtools/create_kyradat/create_kyradat.h
index a6bee6f75c..1d58d7551f 100644
--- a/devtools/create_kyradat/create_kyradat.h
+++ b/devtools/create_kyradat/create_kyradat.h
@@ -131,7 +131,6 @@ enum kExtractID {
k1ConfigStrings,
k1AudioTracks,
- k1AudioTracks2,
k1AudioTracksIntro,
k1CreditsStrings,
diff --git a/devtools/create_kyradat/games.cpp b/devtools/create_kyradat/games.cpp
index afe0c67dbf..e6f0b38c45 100644
--- a/devtools/create_kyradat/games.cpp
+++ b/devtools/create_kyradat/games.cpp
@@ -231,7 +231,6 @@ const int kyra1FloppyNeed[] = {
k1NewGameString,
k1ConfigStrings,
k1AudioTracks,
- k1AudioTracks2,
k1AudioTracksIntro,
-1
};
@@ -317,7 +316,6 @@ const int kyra1FloppyOldNeed[] = {
k1NewGameString,
k1ConfigStrings,
k1AudioTracks,
- k1AudioTracks2,
k1AudioTracksIntro,
-1
};
@@ -405,7 +403,6 @@ const int kyra1CDNeed[] = {
k1NewGameString,
k1ConfigStrings,
k1AudioTracks,
- k1AudioTracks2,
k1AudioTracksIntro,
-1
};
diff --git a/devtools/create_kyradat/resources.cpp b/devtools/create_kyradat/resources.cpp
index 4df6bb8fb8..246811f821 100644
--- a/devtools/create_kyradat/resources.cpp
+++ b/devtools/create_kyradat/resources.cpp
@@ -302,7 +302,6 @@ static const ResourceProvider resourceProviders[] = {
{ k1NewGameString, kKyra1, kPlatformDOS, kNoSpecial, EN_ANY, &k1NewGameStringDOSEnglishProvider },
{ k1ConfigStrings, kKyra1, kPlatformDOS, kNoSpecial, EN_ANY, &k1ConfigStringsDOSEnglishProvider },
{ k1AudioTracks, kKyra1, kPlatformDOS, kNoSpecial, UNK_LANG, &k1AudioTracksDOSProvider },
- { k1AudioTracks2, kKyra1, kPlatformDOS, kNoSpecial, UNK_LANG, &k1AudioTracks2DOSProvider },
{ k1AudioTracksIntro, kKyra1, kPlatformDOS, kNoSpecial, UNK_LANG, &k1AudioTracksIntroDOSProvider },
{ k1IntroStrings, kKyra1, kPlatformDOS, kNoSpecial, DE_DEU, &k1IntroStringsDOSGermanProvider },
{ k1ItemNames, kKyra1, kPlatformDOS, kNoSpecial, DE_DEU, &k1ItemNamesDOSGermanProvider },
@@ -472,7 +471,6 @@ static const ResourceProvider resourceProviders[] = {
{ k1NewGameString, kKyra1, kPlatformDOS, kOldFloppy, RU_RUS, &k1NewGameStringDOSOldFloppyRussianProvider },
{ k1ConfigStrings, kKyra1, kPlatformDOS, kOldFloppy, RU_RUS, &k1ConfigStringsDOSOldFloppyRussianProvider },
{ k1AudioTracks, kKyra1, kPlatformDOS, kOldFloppy, UNK_LANG, &k1AudioTracksDOSOldFloppyProvider },
- { k1AudioTracks2, kKyra1, kPlatformDOS, kOldFloppy, UNK_LANG, &k1AudioTracks2DOSOldFloppyProvider },
{ k1AudioTracksIntro, kKyra1, kPlatformDOS, kOldFloppy, UNK_LANG, &k1AudioTracksIntroDOSOldFloppyProvider },
{ k1KallakWritingSeq, kKyra1, kPlatformDOS, kTalkieVersion, UNK_LANG, &k1KallakWritingSeqDOSCDProvider },
{ k1MalcolmTreeSeq, kKyra1, kPlatformDOS, kTalkieVersion, UNK_LANG, &k1MalcolmTreeSeqDOSCDProvider },
@@ -556,7 +554,6 @@ static const ResourceProvider resourceProviders[] = {
{ k1NewGameString, kKyra1, kPlatformDOS, kTalkieVersion, EN_ANY, &k1NewGameStringDOSCDEnglishProvider },
{ k1ConfigStrings, kKyra1, kPlatformDOS, kTalkieVersion, EN_ANY, &k1ConfigStringsDOSCDEnglishProvider },
{ k1AudioTracks, kKyra1, kPlatformDOS, kTalkieVersion, UNK_LANG, &k1AudioTracksDOSCDProvider },
- { k1AudioTracks2, kKyra1, kPlatformDOS, kTalkieVersion, UNK_LANG, &k1AudioTracks2DOSCDProvider },
{ k1AudioTracksIntro, kKyra1, kPlatformDOS, kTalkieVersion, UNK_LANG, &k1AudioTracksIntroDOSCDProvider },
{ k1IntroStrings, kKyra1, kPlatformDOS, kTalkieVersion, DE_DEU, &k1IntroStringsDOSCDGermanProvider },
{ k1ItemNames, kKyra1, kPlatformDOS, kTalkieVersion, DE_DEU, &k1ItemNamesDOSCDGermanProvider },
diff --git a/devtools/create_kyradat/resources/lok_dos.h b/devtools/create_kyradat/resources/lok_dos.h
index e8d987fe1b..6bc9c2525f 100644
--- a/devtools/create_kyradat/resources/lok_dos.h
+++ b/devtools/create_kyradat/resources/lok_dos.h
@@ -1898,7 +1898,7 @@ static const byte k1OutroReunionSeqDOS[1351] = {
static const ByteProvider k1OutroReunionSeqDOSProvider = { ARRAYSIZE(k1OutroReunionSeqDOS), k1OutroReunionSeqDOS };
-static const char *const k1AudioTracksDOS[8] = {
+static const char *const k1AudioTracksDOS[9] = {
"KYRA1A",
"KYRA1B",
"KYRA2A",
@@ -1906,17 +1906,12 @@ static const char *const k1AudioTracksDOS[8] = {
"KYRA4A",
"KYRA4B",
"KYRA5A",
- "KYRA5B"
+ "KYRA5B",
+ "KYRAMISC"
};
static const StringListProvider k1AudioTracksDOSProvider = { ARRAYSIZE(k1AudioTracksDOS), k1AudioTracksDOS };
-static const char *const k1AudioTracks2DOS[1] = {
- "kyramisc"
-};
-
-static const StringListProvider k1AudioTracks2DOSProvider = { ARRAYSIZE(k1AudioTracks2DOS), k1AudioTracks2DOS };
-
static const char *const k1AudioTracksIntroDOS[1] = {
"intro"
};
diff --git a/devtools/create_kyradat/resources/lok_dos_cd.h b/devtools/create_kyradat/resources/lok_dos_cd.h
index 9550d53d61..dc7a521063 100644
--- a/devtools/create_kyradat/resources/lok_dos_cd.h
+++ b/devtools/create_kyradat/resources/lok_dos_cd.h
@@ -1969,7 +1969,7 @@ static const byte k1OutroReunionSeqDOSCD[1509] = {
static const ByteProvider k1OutroReunionSeqDOSCDProvider = { ARRAYSIZE(k1OutroReunionSeqDOSCD), k1OutroReunionSeqDOSCD };
-static const char *const k1AudioTracksDOSCD[8] = {
+static const char *const k1AudioTracksDOSCD[9] = {
"KYRA1A",
"KYRA1B",
"KYRA2A",
@@ -1977,17 +1977,12 @@ static const char *const k1AudioTracksDOSCD[8] = {
"KYRA4A",
"KYRA4B",
"KYRA5A",
- "KYRA5B"
+ "KYRA5B",
+ "KYRAMISC"
};
static const StringListProvider k1AudioTracksDOSCDProvider = { ARRAYSIZE(k1AudioTracksDOSCD), k1AudioTracksDOSCD };
-static const char *const k1AudioTracks2DOSCD[1] = {
- "kyramisc"
-};
-
-static const StringListProvider k1AudioTracks2DOSCDProvider = { ARRAYSIZE(k1AudioTracks2DOSCD), k1AudioTracks2DOSCD };
-
static const char *const k1AudioTracksIntroDOSCD[2] = {
"intro",
"intro"
diff --git a/devtools/create_kyradat/resources/lok_dos_oldfloppy.h b/devtools/create_kyradat/resources/lok_dos_oldfloppy.h
index e19cb5a6ef..62b1530941 100644
--- a/devtools/create_kyradat/resources/lok_dos_oldfloppy.h
+++ b/devtools/create_kyradat/resources/lok_dos_oldfloppy.h
@@ -1884,7 +1884,7 @@ static const byte k1OutroReunionSeqDOSOldFloppy[1351] = {
static const ByteProvider k1OutroReunionSeqDOSOldFloppyProvider = { ARRAYSIZE(k1OutroReunionSeqDOSOldFloppy), k1OutroReunionSeqDOSOldFloppy };
-static const char *const k1AudioTracksDOSOldFloppy[8] = {
+static const char *const k1AudioTracksDOSOldFloppy[9] = {
"KYRA1A",
"KYRA1B",
"KYRA2A",
@@ -1892,17 +1892,12 @@ static const char *const k1AudioTracksDOSOldFloppy[8] = {
"KYRA4A",
"KYRA4B",
"KYRA5A",
- "KYRA5B"
+ "KYRA5B",
+ "KYRAMISC"
};
static const StringListProvider k1AudioTracksDOSOldFloppyProvider = { ARRAYSIZE(k1AudioTracksDOSOldFloppy), k1AudioTracksDOSOldFloppy };
-static const char *const k1AudioTracks2DOSOldFloppy[1] = {
- "kyramisc"
-};
-
-static const StringListProvider k1AudioTracks2DOSOldFloppyProvider = { ARRAYSIZE(k1AudioTracks2DOSOldFloppy), k1AudioTracks2DOSOldFloppy };
-
static const char *const k1AudioTracksIntroDOSOldFloppy[1] = {
"intro"
};
diff --git a/devtools/create_project/cmake.cpp b/devtools/create_project/cmake.cpp
new file mode 100644
index 0000000000..1423e686be
--- /dev/null
+++ b/devtools/create_project/cmake.cpp
@@ -0,0 +1,324 @@
+/* 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.
+ *
+ */
+
+#include "config.h"
+#include "cmake.h"
+
+#include <algorithm>
+#include <cstring>
+#include <fstream>
+#include <iterator>
+
+namespace CreateProjectTool {
+
+CMakeProvider::CMakeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version)
+ : ProjectProvider(global_warnings, project_warnings, version) {
+}
+
+const CMakeProvider::Library *CMakeProvider::getLibraryFromFeature(const char *feature) const {
+ static const Library s_libraries[] = {
+ { "sdl", "FindSDL", "SDL", "SDL_INCLUDE_DIR", "SDL_LIBRARY", 0 },
+ { "sdl2", 0, "SDL2", "SDL2_INCLUDE_DIRS", "SDL2_LIBRARIES", 0 },
+ { "freetype", "FindFreetype", "Freetype", "FREETYPE_INCLUDE_DIRS", "FREETYPE_LIBRARIES", 0 },
+ { "libz", "FindZLIB", "ZLIB", "ZLIB_INCLUDE_DIRS", "ZLIB_LIBRARIES", 0 },
+ { "png", "FindPNG", "PNG", "PNG_INCLUDE_DIRS", "PNG_LIBRARIES", 0 },
+ { "jpeg", "FindJPEG", "JPEG", "JPEG_INCLUDE_DIRS", "JPEG_LIBRARIES", 0 },
+ { "mpeg2", "FindMPEG2", "MPEG2", "MPEG2_INCLUDE_DIRS", "MPEG2_mpeg2_LIBRARY", 0 },
+ { "flac", 0, 0, 0, 0, "FLAC" },
+ { "mad", 0, 0, 0, 0, "mad" },
+ { "vorbis", 0, 0, 0, 0, "vorbisfile vorbis ogg" },
+ { "theora", 0, 0, 0, 0, "theoradec" },
+ { "fluidsynth",0, 0, 0, 0, "fluidsynth" },
+ { "faad", 0, 0, 0, 0, "faad" }
+ };
+
+ for (unsigned int i = 0; i < sizeof(s_libraries) / sizeof(s_libraries[0]); i++) {
+ if (std::strcmp(feature, s_libraries[i].feature) == 0) {
+ return &s_libraries[i];
+ }
+ }
+
+ return 0;
+}
+
+void CMakeProvider::createWorkspace(const BuildSetup &setup) {
+ std::string filename = setup.outputDir + "/CMakeLists.txt";
+ std::ofstream workspace(filename.c_str());
+ if (!workspace)
+ error("Could not open \"" + filename + "\" for writing");
+
+ workspace << "cmake_minimum_required(VERSION 3.2)\n"
+ "project(" << setup.projectDescription << ")\n\n";
+
+ workspace << "# Define the engines and subengines\n";
+ writeEngines(setup, workspace);
+ writeSubEngines(setup, workspace);
+ workspace << "# Generate options for the engines\n";
+ writeEngineOptions(workspace);
+
+ workspace << "include_directories(${" << setup.projectDescription << "_SOURCE_DIR} ${" << setup.projectDescription << "_SOURCE_DIR}/engines\n"
+ "$ENV{"<<LIBS_DEFINE<<"}/include)\n\n";
+
+ workspace << "# Libraries and features\n";
+ writeFeatureLibSearch(workspace, setup.useSDL2 ? "sdl2" : "sdl");
+ for (FeatureList::const_iterator i = setup.features.begin(), end = setup.features.end(); i != end; ++i) {
+ if (!i->enable || featureExcluded(i->name)) continue;
+
+ writeFeatureLibSearch(workspace, i->name);
+ workspace << "add_definitions(-D" << i->define << ")\n";
+ }
+ workspace << "\n";
+
+ writeWarnings(workspace);
+ writeDefines(setup, workspace);
+ workspace << "# Generate definitions for the engines\n";
+ writeEngineDefinitions(workspace);
+
+ workspace << "# Generate \"engines/plugins_table.h\"\n";
+ writeGeneratePluginsTable(workspace);
+}
+
+void CMakeProvider::writeFeatureLibSearch(std::ofstream &workspace, const char *feature) const {
+ const Library *library = getLibraryFromFeature(feature);
+ if (library) {
+ if (library->module) {
+ workspace << "Include(" << library->module << ")\n";
+ }
+ if (library->package) {
+ workspace << "Find_Package(" << library->package << " REQUIRED)\n";
+ }
+ if (library->includesVar) {
+ workspace << "include_directories(${" << library->includesVar << "})\n";
+ }
+ }
+}
+
+void CMakeProvider::writeEngines(const BuildSetup &setup, std::ofstream &workspace) const {
+ workspace << "set(ENGINES";
+ for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) {
+ // We ignore all sub engines here because they require special handling.
+ if (!i->enable || isSubEngine(i->name, setup.engines)) {
+ continue;
+ }
+
+ std::string engineName;
+ std::transform(i->name.begin(), i->name.end(), std::back_inserter(engineName), toupper);
+
+ workspace << " " << engineName;
+ }
+ workspace << ")\n";
+}
+
+void CMakeProvider::writeSubEngines(const BuildSetup &setup, std::ofstream &workspace) const {
+ for (EngineDescList::const_iterator i = setup.engines.begin(), end = setup.engines.end(); i != end; ++i) {
+ // We ignore all sub engines here because they are handled in the inner loop
+ if (!i->enable || isSubEngine(i->name, setup.engines) || i->subEngines.empty()) {
+ continue;
+ }
+
+ std::string engineName;
+ std::transform(i->name.begin(), i->name.end(), std::back_inserter(engineName), toupper);
+
+ workspace << "set(SUB_ENGINES_" << engineName;
+ for (StringList::const_iterator j = i->subEngines.begin(), subEnd = i->subEngines.end(); j != subEnd; ++j) {
+ const EngineDesc &subEngine = findEngineDesc(*j, setup.engines);
+ if (!subEngine.enable) continue;
+
+ std::string subEngineName;
+ std::transform(j->begin(), j->end(), std::back_inserter(subEngineName), toupper);
+
+ workspace << " " << subEngineName;
+ }
+ workspace << ")\n";
+ }
+
+ workspace << "\n";
+}
+
+void CMakeProvider::createProjectFile(const std::string &name, const std::string &, const BuildSetup &setup, const std::string &moduleDir,
+ const StringList &includeList, const StringList &excludeList) {
+
+ const std::string projectFile = setup.outputDir + "/CMakeLists.txt";
+ std::ofstream project(projectFile.c_str(), std::ofstream::out | std::ofstream::app);
+ if (!project)
+ error("Could not open \"" + projectFile + "\" for writing");
+
+ if (name == setup.projectName) {
+ project << "add_executable(" << name << "\n";
+ } else {
+ std::string engineName;
+ std::transform(name.begin(), name.end(), std::back_inserter(engineName), toupper);
+
+ project << "if (ENABLE_" << engineName << ")\n";
+ project << "add_library(" << name << "\n";
+ }
+
+ std::string modulePath;
+ if (!moduleDir.compare(0, setup.srcDir.size(), setup.srcDir)) {
+ modulePath = moduleDir.substr(setup.srcDir.size());
+ if (!modulePath.empty() && modulePath.at(0) == '/')
+ modulePath.erase(0, 1);
+ }
+
+ if (modulePath.size())
+ addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix + '/' + modulePath);
+ else
+ addFilesToProject(moduleDir, project, includeList, excludeList, setup.filePrefix);
+
+
+ project << ")\n";
+ if (name != setup.projectName) {
+ project << "endif()\n";
+ }
+
+ project << "# Libraries\n";
+ if (name == setup.projectName) {
+ const Library *sdlLibrary = getLibraryFromFeature(setup.useSDL2 ? "sdl2" : "sdl");
+ project << "target_link_libraries(" << name << " ${" << sdlLibrary->librariesVar << "})\n";
+
+ for (FeatureList::const_iterator i = setup.features.begin(), end = setup.features.end(); i != end; ++i) {
+ if (!i->enable || featureExcluded(i->name)) continue;
+
+ const Library *library = getLibraryFromFeature(i->name);
+ if (!library) continue;
+
+ if (library->librariesVar) {
+ project << "target_link_libraries(" << name << " ${" << library->librariesVar << "})\n";
+ } else {
+ project << "target_link_libraries(" << name << " " << library->libraries << ")\n";
+ }
+ }
+ project << "if (WIN32)\n";
+ project << " target_sources(" << name << " PUBLIC dists/" << name << ".rc)\n";
+ project << " target_link_libraries(" << name << " winmm)\n";
+ project << "endif()\n";
+ project << "\n";
+
+ project << "# Engines libraries handling\n";
+ writeEnginesLibrariesHandling(setup, project);
+
+ project << "set_property(TARGET " << name << " PROPERTY CXX_STANDARD 11)\n";
+ project << "set_property(TARGET " << name << " PROPERTY CXX_STANDARD_REQUIRED ON)\n";
+ }
+}
+
+void CMakeProvider::writeWarnings(std::ofstream &output) const {
+ output << "SET (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS}";
+ for (StringList::const_iterator i = _globalWarnings.begin(); i != _globalWarnings.end(); ++i) {
+ output << " " << *i;
+ }
+ output << "\")\n";
+}
+
+void CMakeProvider::writeDefines(const BuildSetup &setup, std::ofstream &output) const {
+ output << "if (WIN32)\n";
+ output << " add_definitions(-DWIN32)\n";
+ output << "else()\n";
+ output << " add_definitions(-DPOSIX)\n";
+ output << "endif()\n";
+
+ output << "if (CMAKE_SIZEOF_VOID_P MATCHES 8)\n";
+ output << " add_definitions(-DSCUMM_64BITS)\n";
+ output << "endif()\n";
+
+ output << "add_definitions(-DSDL_BACKEND)\n\n";
+}
+
+void CMakeProvider::writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
+ const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix) {
+
+ for (FileNode::NodeList::const_iterator i = dir.children.begin(); i != dir.children.end(); ++i) {
+ const FileNode *node = *i;
+
+ if (!node->children.empty()) {
+ writeFileListToProject(*node, projectFile, indentation + 1, duplicate, objPrefix + node->name + '_', filePrefix + node->name + '/');
+ } else {
+ std::string name, ext;
+ splitFilename(node->name, name, ext);
+ projectFile << "\t" << filePrefix + node->name << "\n";
+ }
+ }
+}
+
+const char *CMakeProvider::getProjectExtension() {
+ return ".txt";
+}
+
+void CMakeProvider::writeEngineOptions(std::ofstream &workspace) const {
+ workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
+ workspace << " OPTION(ENABLE_${ENGINE} \"Enable ${ENGINE}\" ON)\n";
+ workspace << "endforeach(ENGINE)\n\n";
+}
+
+void CMakeProvider::writeGeneratePluginsTable(std::ofstream &workspace) const {
+ workspace << "file(REMOVE \"engines/plugins_table.h\")\n";
+ workspace << "file(APPEND \"engines/plugins_table.h\" \"/* This file is automatically generated by CMake */\\n\")\n";
+ workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
+ workspace << " if (ENABLE_${ENGINE})\n";
+ workspace << " file(APPEND \"engines/plugins_table.h\" \"#if PLUGIN_ENABLED_STATIC(${ENGINE})\\n\")\n";
+ workspace << " file(APPEND \"engines/plugins_table.h\" \"LINK_PLUGIN(${ENGINE})\\n\")\n";
+ workspace << " file(APPEND \"engines/plugins_table.h\" \"#endif\\n\")\n";
+ workspace << " endif()\n";
+ workspace << "endforeach()\n\n";
+}
+
+void CMakeProvider::writeEnginesLibrariesHandling(const BuildSetup &setup, std::ofstream &workspace) const {
+ workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
+ workspace << " if (ENABLE_${ENGINE})\n";
+ workspace << " string(TOLOWER ${ENGINE} ENGINE_LIB)\n\n";
+ workspace << " # Enable C++11\n";
+ workspace << " set_property(TARGET ${ENGINE_LIB} PROPERTY CXX_STANDARD 11)\n";
+ workspace << " set_property(TARGET ${ENGINE_LIB} PROPERTY CXX_STANDARD_REQUIRED ON)\n\n";
+ workspace << " # Link against the engine\n";
+ workspace << " target_link_libraries("<< setup.projectName <<" ${ENGINE_LIB})\n";
+ workspace << " endif()\n";
+ workspace << "endforeach()\n\n";
+}
+
+void CMakeProvider::writeEngineDefinitions(std::ofstream &workspace) const {
+ workspace << "foreach(ENGINE IN LISTS ENGINES)\n";
+ workspace << " if (ENABLE_${ENGINE})\n";
+ workspace << " add_definitions(-DENABLE_${ENGINE})\n";
+ workspace << " foreach(SUB_ENGINE IN LISTS SUB_ENGINES_${ENGINE})\n";
+ workspace << " add_definitions(-DENABLE_${SUB_ENGINE})\n";;
+ workspace << " endforeach(SUB_ENGINE)\n";
+ workspace << " endif()\n";
+ workspace << "endforeach()\n\n";
+}
+
+bool CMakeProvider::featureExcluded(const char *name) const {
+ return std::strcmp(name, "nasm") == 0 ||
+ std::strcmp(name, "updates") == 0 ; // NASM is not supported for now
+}
+
+const EngineDesc &CMakeProvider::findEngineDesc(const std::string &name, const EngineDescList &engines) const {
+ for (EngineDescList::const_iterator i = engines.begin(), end = engines.end(); i != end; ++i) {
+ if (i->name == name) {
+ return *i;
+ }
+
+ }
+
+ error("Unable to find requested engine");
+}
+
+} // End of CreateProjectTool namespace
diff --git a/devtools/create_project/cmake.h b/devtools/create_project/cmake.h
new file mode 100644
index 0000000000..ec7ff565c9
--- /dev/null
+++ b/devtools/create_project/cmake.h
@@ -0,0 +1,85 @@
+/* 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.
+ *
+ */
+
+#ifndef TOOLS_CREATE_PROJECT_CMAKE_H
+#define TOOLS_CREATE_PROJECT_CMAKE_H
+
+#include "create_project.h"
+
+namespace CreateProjectTool {
+
+/**
+ * A ProjectProvider used to generate CMake project descriptions
+ *
+ * Generated CMake projects are minimal, and will only work with GCC.
+ */
+class CMakeProvider : public ProjectProvider {
+public:
+ CMakeProvider(StringList &global_warnings, std::map<std::string, StringList> &project_warnings, const int version = 0);
+
+protected:
+
+ void createWorkspace(const BuildSetup &setup);
+
+ void createOtherBuildFiles(const BuildSetup &) {}
+
+ void addResourceFiles(const BuildSetup &setup, StringList &includeList, StringList &excludeList) {}
+
+ void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir,
+ const StringList &includeList, const StringList &excludeList);
+
+ void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation,
+ const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix);
+
+ const char *getProjectExtension();
+
+private:
+ /**
+ * CMake properties for a library required by a feature
+ */
+ struct Library {
+ const char *feature;
+ const char *module;
+ const char *package;
+ const char *includesVar;
+ const char *librariesVar;
+ const char *libraries;
+ };
+
+ const Library *getLibraryFromFeature(const char *feature) const;
+
+ void writeWarnings(std::ofstream &output) const;
+ void writeDefines(const BuildSetup &setup, std::ofstream &output) const;
+ void writeEngines(const BuildSetup &setup, std::ofstream &workspace) const;
+ void writeSubEngines(const BuildSetup &setup, std::ofstream &workspace) const;
+ void writeEngineOptions(std::ofstream &workspace) const;
+ void writeGeneratePluginsTable(std::ofstream &workspace) const;
+ void writeEnginesLibrariesHandling(const BuildSetup &setup, std::ofstream &workspace) const;
+ void writeEngineDefinitions(std::ofstream &workspace) const;
+ void writeFeatureLibSearch(std::ofstream &workspace, const char *feature) const;
+ bool featureExcluded(const char *name) const;
+ const EngineDesc &findEngineDesc(const std::string &name, const EngineDescList &engines) const;
+};
+
+} // End of CreateProjectTool namespace
+
+#endif // TOOLS_CREATE_PROJECT_CMAKE_H
diff --git a/devtools/create_project/cmake/CMakeLists.txt b/devtools/create_project/cmake/CMakeLists.txt
new file mode 100644
index 0000000000..2646b89d2d
--- /dev/null
+++ b/devtools/create_project/cmake/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 3.2)
+project(create_project)
+
+
+set(SOURCE_FILES
+ ../cmake.cpp
+ ../cmake.h
+ ../codeblocks.cpp
+ ../codeblocks.h
+ ../create_project.cpp
+ ../create_project.h
+ ../msbuild.cpp
+ ../msbuild.h
+ ../msvc.cpp
+ ../msvc.h
+ ../visualstudio.cpp
+ ../visualstudio.h
+ ../xcode.cpp
+ ../xcode.h
+ )
+
+add_executable(create_project ${SOURCE_FILES})
+
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index 65b7601a54..7e2cad0901 100644
--- a/devtools/create_project/create_project.cpp
+++ b/devtools/create_project/create_project.cpp
@@ -31,6 +31,7 @@
#include "config.h"
#include "create_project.h"
+#include "cmake.h"
#include "codeblocks.h"
#include "msvc.h"
#include "visualstudio.h"
@@ -53,7 +54,7 @@
#define USE_WIN32_API
#endif
-#ifdef USE_WIN32_API
+#if (defined(_WIN32) || defined(WIN32))
#include <windows.h>
#else
#include <sstream>
@@ -83,10 +84,18 @@ std::string unifyPath(const std::string &path);
* @param exe Name of the executable.
*/
void displayHelp(const char *exe);
+
+/**
+ * Build a list of options to enable or disable GCC warnings
+ *
+ * @param globalWarnings Resulting list of warnings
+ */
+void addGCCWarnings(StringList &globalWarnings);
} // End of anonymous namespace
enum ProjectType {
kProjectNone,
+ kProjectCMake,
kProjectCodeBlocks,
kProjectMSVC,
kProjectXcode
@@ -125,7 +134,6 @@ int main(int argc, char *argv[]) {
ProjectType projectType = kProjectNone;
int msvcVersion = 12;
- bool useSDL2 = false;
// Parse command line arguments
using std::cout;
@@ -142,6 +150,14 @@ int main(int argc, char *argv[]) {
return 0;
+ } else if (!std::strcmp(argv[i], "--cmake")) {
+ if (projectType != kProjectNone) {
+ std::cerr << "ERROR: You cannot pass more than one project type!\n";
+ return -1;
+ }
+
+ projectType = kProjectCMake;
+
} else if (!std::strcmp(argv[i], "--codeblocks")) {
if (projectType != kProjectNone) {
std::cerr << "ERROR: You cannot pass more than one project type!\n";
@@ -269,7 +285,7 @@ int main(int argc, char *argv[]) {
} else if (!std::strcmp(argv[i], "--tests")) {
setup.tests = true;
} else if (!std::strcmp(argv[i], "--sdl2")) {
- useSDL2 = true;
+ setup.useSDL2 = true;
} else {
std::cerr << "ERROR: Unknown parameter \"" << argv[i] << "\"\n";
return -1;
@@ -335,10 +351,7 @@ int main(int argc, char *argv[]) {
StringList featureDefines = getFeatureDefines(setup.features);
setup.defines.splice(setup.defines.begin(), featureDefines);
- // Windows only has support for the SDL backend, so we hardcode it here (along with winmm)
- if (projectType != kProjectXcode) {
- setup.defines.push_back("WIN32");
- } else {
+ if (projectType == kProjectXcode) {
setup.defines.push_back("POSIX");
// Define both MACOSX, and IPHONE, but only one of them will be associated to the
// correct target by the Xcode project provider.
@@ -347,13 +360,42 @@ int main(int argc, char *argv[]) {
// the files, according to the target.
setup.defines.push_back("MACOSX");
setup.defines.push_back("IPHONE");
+ } else if (projectType == kProjectMSVC || projectType == kProjectCodeBlocks) {
+ // Windows only has support for the SDL backend, so we hardcode it here (along with winmm)
+ setup.defines.push_back("WIN32");
+ } else {
+ // As a last resort, select the backend files to build based on the platform used to build create_project.
+ // This is broken when cross compiling.
+#if defined(_WIN32) || defined(WIN32)
+ setup.defines.push_back("WIN32");
+#else
+ setup.defines.push_back("POSIX");
+#endif
+ }
+
+ bool updatesEnabled = false;
+ for (FeatureList::const_iterator i = setup.features.begin(); i != setup.features.end(); ++i) {
+ if (i->enable && !strcmp(i->name, "updates"))
+ updatesEnabled = true;
+ }
+ if (updatesEnabled) {
+ setup.defines.push_back("USE_SPARKLE");
+ if (projectType != kProjectXcode)
+ setup.libraries.push_back("winsparkle");
+ else
+ setup.libraries.push_back("sparkle");
}
+
setup.defines.push_back("SDL_BACKEND");
- if (!useSDL2) {
- cout << "\nLinking to SDL 1.2\n\n";
+ if (!setup.useSDL2) {
+ cout << "\nBuilding against SDL 1.2\n\n";
setup.libraries.push_back("sdl");
} else {
- cout << "\nLinking to SDL 2.0\n\n";
+ cout << "\nBuilding against SDL 2.0\n\n";
+ // TODO: This also defines USE_SDL2 in the preprocessor, we don't do
+ // this in our configure/make based build system. Adapt create_project
+ // to replicate this behavior.
+ setup.defines.push_back("USE_SDL2");
setup.libraries.push_back("sdl2");
}
setup.libraries.push_back("winmm");
@@ -380,49 +422,25 @@ int main(int argc, char *argv[]) {
std::cerr << "ERROR: No project type has been specified!\n";
return -1;
+ case kProjectCMake:
+ if (setup.devTools || setup.tests) {
+ std::cerr << "ERROR: Building tools or tests is not supported for the CMake project type!\n";
+ return -1;
+ }
+
+ addGCCWarnings(globalWarnings);
+
+ provider = new CreateProjectTool::CMakeProvider(globalWarnings, projectWarnings);
+
+ break;
+
case kProjectCodeBlocks:
if (setup.devTools || setup.tests) {
std::cerr << "ERROR: Building tools or tests is not supported for the CodeBlocks project type!\n";
return -1;
}
- ////////////////////////////////////////////////////////////////////////////
- // Code::Blocks is using GCC behind the scenes, so we need to pass a list
- // of options to enable or disable warnings
- ////////////////////////////////////////////////////////////////////////////
- //
- // -Wall
- // enable all warnings
- //
- // -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
- // disable annoying and not-so-useful warnings
- //
- // -Wpointer-arith -Wcast-qual -Wcast-align
- // -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
- // enable even more warnings...
- //
- // -fno-rtti -fno-exceptions -fcheck-new
- // disable RTTI and exceptions, and enable checking of pointers returned
- // by "new"
- //
- ////////////////////////////////////////////////////////////////////////////
-
- globalWarnings.push_back("-Wall");
- globalWarnings.push_back("-Wno-long-long");
- globalWarnings.push_back("-Wno-multichar");
- globalWarnings.push_back("-Wno-unknown-pragmas");
- globalWarnings.push_back("-Wno-reorder");
- globalWarnings.push_back("-Wpointer-arith");
- globalWarnings.push_back("-Wcast-qual");
- globalWarnings.push_back("-Wcast-align");
- globalWarnings.push_back("-Wshadow");
- globalWarnings.push_back("-Wimplicit");
- globalWarnings.push_back("-Wnon-virtual-dtor");
- globalWarnings.push_back("-Wwrite-strings");
- // The following are not warnings at all... We should consider adding them to
- // a different list of parameters.
- globalWarnings.push_back("-fno-exceptions");
- globalWarnings.push_back("-fcheck-new");
+ addGCCWarnings(globalWarnings);
provider = new CreateProjectTool::CodeBlocksProvider(globalWarnings, projectWarnings);
@@ -636,6 +654,7 @@ void displayHelp(const char *exe) {
" Additionally there are the following switches for changing various settings:\n"
"\n"
"Project specific settings:\n"
+ " --cmake build CMake project files\n"
" --codeblocks build Code::Blocks project files\n"
" --msvc build Visual Studio project files\n"
" --xcode build XCode project files\n"
@@ -690,6 +709,41 @@ void displayHelp(const char *exe) {
cout.setf(std::ios_base::right, std::ios_base::adjustfield);
}
+void addGCCWarnings(StringList &globalWarnings) {
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // -Wall
+ // enable all warnings
+ //
+ // -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
+ // disable annoying and not-so-useful warnings
+ //
+ // -Wpointer-arith -Wcast-qual -Wcast-align
+ // -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
+ // enable even more warnings...
+ //
+ // -fno-exceptions -fcheck-new
+ // disable exceptions, and enable checking of pointers returned by "new"
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ globalWarnings.push_back("-Wall");
+ globalWarnings.push_back("-Wno-long-long");
+ globalWarnings.push_back("-Wno-multichar");
+ globalWarnings.push_back("-Wno-unknown-pragmas");
+ globalWarnings.push_back("-Wno-reorder");
+ globalWarnings.push_back("-Wpointer-arith");
+ globalWarnings.push_back("-Wcast-qual");
+ globalWarnings.push_back("-Wcast-align");
+ globalWarnings.push_back("-Wshadow");
+ globalWarnings.push_back("-Wnon-virtual-dtor");
+ globalWarnings.push_back("-Wwrite-strings");
+ // The following are not warnings at all... We should consider adding them to
+ // a different list of parameters.
+ globalWarnings.push_back("-fno-exceptions");
+ globalWarnings.push_back("-fcheck-new");
+}
+
/**
* Parse the configure.engine file of a given engine directory and return a
* list of all defined engines.
@@ -935,17 +989,17 @@ TokenList tokenize(const std::string &input, char separator) {
namespace {
const Feature s_features[] = {
// Libraries
- { "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" },
- { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" },
+ { "libz", "USE_ZLIB", "zlib", true, "zlib (compression) support" },
+ { "mad", "USE_MAD", "libmad", true, "libmad (MP3) support" },
{ "vorbis", "USE_VORBIS", "libvorbisfile_static libvorbis_static libogg_static", true, "Ogg Vorbis support" },
{ "flac", "USE_FLAC", "libFLAC_static win_utf8_io_static", true, "FLAC support" },
- { "png", "USE_PNG", "libpng", true, "libpng support" },
+ { "png", "USE_PNG", "libpng16", true, "libpng support" },
{ "faad", "USE_FAAD", "libfaad", false, "AAC support" },
{ "mpeg2", "USE_MPEG2", "libmpeg2", false, "MPEG-2 support" },
- { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" },
- { "freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" },
- { "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" },
- {"fluidsynth", "USE_FLUIDSYNTH", "libfluidsynth", true, "FluidSynth support" },
+ { "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" },
+ { "freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" },
+ { "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" },
+ {"fluidsynth", "USE_FLUIDSYNTH", "libfluidsynth", true, "FluidSynth support" },
// Feature flags
{ "bink", "USE_BINK", "", true, "Bink video support" },
@@ -954,12 +1008,14 @@ const Feature s_features[] = {
{ "16bit", "USE_RGB_COLOR", "", true, "16bit color support" },
{ "mt32emu", "USE_MT32EMU", "", true, "integrated MT-32 emulator" },
{ "nasm", "USE_NASM", "", true, "IA-32 assembly support" }, // This feature is special in the regard, that it needs additional handling.
- { "opengl", "USE_OPENGL", "opengl32", true, "OpenGL support" },
+ { "opengl", "USE_OPENGL", "", true, "OpenGL support" },
+ { "opengles", "USE_GLES", "", true, "forced OpenGL ES mode" },
{ "taskbar", "USE_TASKBAR", "", true, "Taskbar integration support" },
{ "translation", "USE_TRANSLATION", "", true, "Translation support" },
{ "vkeybd", "ENABLE_VKEYBD", "", false, "Virtual keyboard support"},
{ "keymapper", "ENABLE_KEYMAPPER", "", false, "Keymapper support"},
{ "eventrecorder", "ENABLE_EVENTRECORDER", "", false, "Event recorder support"},
+ { "updates", "USE_UPDATES", "", false, "Updates support"},
{ "langdetect", "USE_DETECTLANG", "", true, "System language detection support" } // This feature actually depends on "translation", there
// is just no current way of properly detecting this...
};
@@ -1156,7 +1212,7 @@ bool compareNodes(const FileNode *l, const FileNode *r) {
FileList listDirectory(const std::string &dir) {
FileList result;
-#ifdef USE_WIN32_API
+#if defined(_WIN32) || defined(WIN32)
WIN32_FIND_DATA fileInformation;
HANDLE fileHandle = FindFirstFile((dir + "/*").c_str(), &fileInformation);
diff --git a/devtools/create_project/create_project.h b/devtools/create_project/create_project.h
index fb207f3f59..1e417d485b 100644
--- a/devtools/create_project/create_project.h
+++ b/devtools/create_project/create_project.h
@@ -229,15 +229,17 @@ struct BuildSetup {
StringList testDirs; ///< List of all folders containing tests
bool devTools; ///< Generate project files for the tools
- bool tests; ///< Generate project files for the tests
+ bool tests; ///< Generate project files for the tests
bool runBuildEvents; ///< Run build events as part of the build (generate revision number and copy engine/theme data & needed files to the build folder
bool createInstaller; ///< Create NSIS installer after the build
+ bool useSDL2; ///< Whether to use SDL2 or not.
BuildSetup() {
devTools = false;
tests = false;
runBuildEvents = false;
createInstaller = false;
+ useSDL2 = false;
}
};
diff --git a/devtools/create_project/module.mk b/devtools/create_project/module.mk
index 0db070fa7c..bb7bdcc9b0 100644
--- a/devtools/create_project/module.mk
+++ b/devtools/create_project/module.mk
@@ -2,6 +2,7 @@
MODULE := devtools/create_project
MODULE_OBJS := \
+ cmake.o \
create_project.o \
codeblocks.o \
msvc.o \
diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp
index a326bd721a..2c6a89543f 100644
--- a/devtools/create_project/msbuild.cpp
+++ b/devtools/create_project/msbuild.cpp
@@ -319,12 +319,6 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s
for (StringList::const_iterator i = setup.libraries.begin(); i != setup.libraries.end(); ++i)
libraries += *i + ".lib;";
- if (_version == 14) {
- std::string debug = isRelease ? "" : "d";
- libraries += "libvcruntime" + debug + ".lib;";
- libraries += "libucrt" + debug + ".lib;";
- }
-
project << "\t\t<Link>\n"
"\t\t\t<OutputFile>$(OutDir)" << ((setup.devTools || setup.tests) ? name : setup.projectName) << ".exe</OutputFile>\n"
"\t\t\t<AdditionalDependencies>" << libraries << "%(AdditionalDependencies)</AdditionalDependencies>\n"
@@ -370,17 +364,17 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea
"<Project DefaultTargets=\"Build\" ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n"
"\t<PropertyGroup>\n"
"\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_Global</_PropertySheetDisplayName>\n"
- "\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(ExecutablePath)</ExecutablePath>\n"
- "\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(LibraryPath)</LibraryPath>\n"
- "\t\t<IncludePath>$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\SDL;$(IncludePath)</IncludePath>\n"
+ "\t\t<ExecutablePath>$(" << LIBS_DEFINE << ")\\bin;$(" << LIBS_DEFINE << ")\\bin\\" << (bits == 32 ? "x86" : "x64") << ";$(ExecutablePath)</ExecutablePath>\n"
+ "\t\t<LibraryPath>$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << ";$(" << LIBS_DEFINE << ")\\lib\\" << (bits == 32 ? "x86" : "x64") << "\\$(Configuration);$(LibraryPath)</LibraryPath>\n"
+ "\t\t<IncludePath>$(" << LIBS_DEFINE << ")\\include;$(" << LIBS_DEFINE << ")\\include\\" << (setup.useSDL2 ? "SDL2" : "SDL") << ";$(IncludePath)</IncludePath>\n"
"\t\t<OutDir>$(Configuration)" << bits << "\\</OutDir>\n"
- "\t\t<IntDir>$(Configuration)" << bits << "/$(ProjectName)\\</IntDir>\n"
+ "\t\t<IntDir>$(Configuration)" << bits << "\\$(ProjectName)\\</IntDir>\n"
"\t</PropertyGroup>\n"
"\t<ItemDefinitionGroup>\n"
"\t\t<ClCompile>\n"
"\t\t\t<DisableLanguageExtensions>true</DisableLanguageExtensions>\n"
"\t\t\t<DisableSpecificWarnings>" << warnings << ";%(DisableSpecificWarnings)</DisableSpecificWarnings>\n"
- "\t\t\t<AdditionalIncludeDirectories>$(" << LIBS_DEFINE << ")\\include;.;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
+ "\t\t\t<AdditionalIncludeDirectories>.;" << prefix << ";" << prefix << "\\engines;" << (setup.tests ? prefix + "\\test\\cxxtest;" : "") << "$(TargetDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n"
"\t\t\t<PreprocessorDefinitions>" << definesList << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
"\t\t\t<ExceptionHandling>" << ((setup.devTools || setup.tests) ? "Sync" : "") << "</ExceptionHandling>\n";
@@ -437,10 +431,14 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b
"\t\t\t<StringPooling>true</StringPooling>\n"
"\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n"
"\t\t\t<DebugInformationFormat></DebugInformationFormat>\n"
- "\t\t\t<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n"
+ "\t\t\t<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n"
"\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n"
"\t\t</ClCompile>\n"
+ "\t\t<Lib>\n"
+ "\t\t\t<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>\n"
+ "\t\t</Lib>\n"
"\t\t<Link>\n"
+ "\t\t\t<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>\n"
"\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n"
"\t\t\t<SetChecksum>true</SetChecksum>\n";
} else {
@@ -448,11 +446,17 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b
"\t\t\t<PreprocessorDefinitions>WIN32;" << (configuration == "LLVM" ? "_CRT_SECURE_NO_WARNINGS;" : "") << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n"
"\t\t\t<MinimalRebuild>true</MinimalRebuild>\n"
"\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n"
- "\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n"
+ "\t\t\t<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n"
"\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n"
- "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n"
- "\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n" // For x64 format Edit and continue is not supported, thus we default to Program Database
- "\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n";
+ "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n";
+ if (_version >= 14) {
+ // Since MSVC 2015 Edit and Continue is support for x64 too.
+ properties << "\t\t\t<DebugInformationFormat>" << "EditAndContinue" << "</DebugInformationFormat>\n";
+ } else {
+ // Older MSVC versions did not support Edit and Continue for x64, thus we do not use it.
+ properties << "\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n";
+ }
+ properties << "\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n";
if (configuration == "LLVM") {
// FIXME The LLVM cl wrapper does not seem to work properly with the $(TargetDir) path so we hard-code the build folder until the issue is resolved
@@ -463,8 +467,7 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b
properties << "\t\t</ClCompile>\n"
"\t\t<Link>\n"
"\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n"
- "\t\t\t<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n"
- "\t\t\t<IgnoreSpecificDefaultLibraries>libcmt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n";
+ "\t\t\t<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n";
}
properties << "\t\t</Link>\n"
diff --git a/devtools/create_project/msvc10/create_project.vcxproj b/devtools/create_project/msvc10/create_project.vcxproj
index 80dfd5e8d3..700c4bb283 100644
--- a/devtools/create_project/msvc10/create_project.vcxproj
+++ b/devtools/create_project/msvc10/create_project.vcxproj
@@ -95,6 +95,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\cmake.cpp" />
<ClCompile Include="..\codeblocks.cpp" />
<ClCompile Include="..\create_project.cpp" />
<ClCompile Include="..\msbuild.cpp" />
@@ -103,6 +104,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
<ClCompile Include="..\xcode.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\cmake.h" />
<ClInclude Include="..\codeblocks.h" />
<ClInclude Include="..\config.h" />
<ClInclude Include="..\create_project.h" />
diff --git a/devtools/create_project/msvc11/create_project.vcxproj b/devtools/create_project/msvc11/create_project.vcxproj
index 8bbd25e9ba..09392a43e3 100644
--- a/devtools/create_project/msvc11/create_project.vcxproj
+++ b/devtools/create_project/msvc11/create_project.vcxproj
@@ -101,6 +101,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\cmake.cpp" />
<ClCompile Include="..\codeblocks.cpp" />
<ClCompile Include="..\create_project.cpp" />
<ClCompile Include="..\msbuild.cpp" />
@@ -109,6 +110,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
<ClCompile Include="..\xcode.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\cmake.h" />
<ClInclude Include="..\codeblocks.h" />
<ClInclude Include="..\config.h" />
<ClInclude Include="..\create_project.h" />
diff --git a/devtools/create_project/msvc12/create_project.vcxproj b/devtools/create_project/msvc12/create_project.vcxproj
index 6da1556547..3b38972e51 100644
--- a/devtools/create_project/msvc12/create_project.vcxproj
+++ b/devtools/create_project/msvc12/create_project.vcxproj
@@ -102,6 +102,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\cmake.cpp" />
<ClCompile Include="..\codeblocks.cpp" />
<ClCompile Include="..\create_project.cpp" />
<ClCompile Include="..\msbuild.cpp" />
@@ -110,6 +111,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
<ClCompile Include="..\xcode.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\cmake.h" />
<ClInclude Include="..\codeblocks.h" />
<ClInclude Include="..\config.h" />
<ClInclude Include="..\create_project.h" />
diff --git a/devtools/create_project/msvc14/create_project.vcxproj b/devtools/create_project/msvc14/create_project.vcxproj
index 3c0345f49c..839c834bb8 100644
--- a/devtools/create_project/msvc14/create_project.vcxproj
+++ b/devtools/create_project/msvc14/create_project.vcxproj
@@ -192,6 +192,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\cmake.cpp" />
<ClCompile Include="..\codeblocks.cpp" />
<ClCompile Include="..\create_project.cpp" />
<ClCompile Include="..\msbuild.cpp" />
@@ -200,6 +201,7 @@ xcopy /Y "$(TargetPath)" "$(SolutionDir)\..\..\..\dists\iphone\"</Command>
<ClCompile Include="..\xcode.cpp" />
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="..\cmake.h" />
<ClInclude Include="..\codeblocks.h" />
<ClInclude Include="..\config.h" />
<ClInclude Include="..\create_project.h" />
diff --git a/devtools/create_project/msvc9/create_project.vcproj b/devtools/create_project/msvc9/create_project.vcproj
index dc914248fb..eaa72099cc 100644
--- a/devtools/create_project/msvc9/create_project.vcproj
+++ b/devtools/create_project/msvc9/create_project.vcproj
@@ -170,6 +170,10 @@
>
</File>
<File
+ RelativePath="..\cmake.cpp"
+ >
+ </File>
+ <File
RelativePath="..\codeblocks.cpp"
>
</File>
@@ -200,6 +204,10 @@
>
</File>
<File
+ RelativePath="..\cmake.h"
+ >
+ </File>
+ <File
RelativePath="..\codeblocks.h"
>
</File>
diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp
index a43730fbe2..bfe7f522f0 100644
--- a/devtools/create_project/xcode.cpp
+++ b/devtools/create_project/xcode.cpp
@@ -447,9 +447,6 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) {
DEF_SYSFRAMEWORK("UIKit");
DEF_SYSTBD("libiconv");
- // Optionals:
- DEF_SYSFRAMEWORK("OpenGL");
-
// Local libraries
DEF_LOCALLIB_STATIC("libFLAC");
DEF_LOCALLIB_STATIC("libmad");
@@ -570,8 +567,6 @@ void XcodeProvider::setupFrameworksBuildPhase(const BuildSetup &setup) {
frameworks_osx.push_back("IOKit.framework");
frameworks_osx.push_back("Cocoa.framework");
frameworks_osx.push_back("AudioUnit.framework");
- // Optionals:
- frameworks_osx.push_back("OpenGL.framework");
order = 0;
for (ValueList::iterator framework = frameworks_osx.begin(); framework != frameworks_osx.end(); framework++) {
@@ -932,7 +927,11 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
ADD_SETTING_LIST(scummvmOSX_Debug, "GCC_PREPROCESSOR_DEFINITIONS", scummvmOSX_defines, kSettingsNoQuote | kSettingsAsList, 5);
ADD_SETTING_QUOTE(scummvmOSX_Debug, "GCC_VERSION", "");
ValueList scummvmOSX_HeaderPaths;
- scummvmOSX_HeaderPaths.push_back("/opt/local/include/SDL");
+ if (setup.useSDL2) {
+ scummvmOSX_HeaderPaths.push_back("/opt/local/include/SDL2");
+ } else {
+ scummvmOSX_HeaderPaths.push_back("/opt/local/include/SDL");
+ }
scummvmOSX_HeaderPaths.push_back("/opt/local/include");
scummvmOSX_HeaderPaths.push_back("/opt/local/include/freetype2");
scummvmOSX_HeaderPaths.push_back("include/");
@@ -948,7 +947,6 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
ADD_SETTING_LIST(scummvmOSX_Debug, "LIBRARY_SEARCH_PATHS", scummvmOSX_LibPaths, kSettingsNoQuote | kSettingsAsList, 5);
ADD_SETTING_QUOTE(scummvmOSX_Debug, "OTHER_CFLAGS", "");
ValueList scummvmOSX_LdFlags;
- scummvmOSX_LdFlags.push_back("-lSDLmain");
scummvmOSX_LdFlags.push_back("-logg");
scummvmOSX_LdFlags.push_back("-lpng");
scummvmOSX_LdFlags.push_back("-ljpeg");
@@ -958,7 +956,13 @@ void XcodeProvider::setupBuildConfiguration(const BuildSetup &setup) {
scummvmOSX_LdFlags.push_back("-lvorbis");
scummvmOSX_LdFlags.push_back("-lmad");
scummvmOSX_LdFlags.push_back("-lFLAC");
- scummvmOSX_LdFlags.push_back("-lSDL");
+ if (setup.useSDL2) {
+ scummvmOSX_LdFlags.push_back("-lSDL2main");
+ scummvmOSX_LdFlags.push_back("-lSDL2");
+ } else {
+ scummvmOSX_LdFlags.push_back("-lSDLmain");
+ scummvmOSX_LdFlags.push_back("-lSDL");
+ }
scummvmOSX_LdFlags.push_back("-lz");
ADD_SETTING_LIST(scummvmOSX_Debug, "OTHER_LDFLAGS", scummvmOSX_LdFlags, kSettingsAsList, 5);
ADD_SETTING(scummvmOSX_Debug, "PREBINDING", "NO");
diff --git a/devtools/credits.pl b/devtools/credits.pl
index c67793cbfa..9cc5ad4227 100755
--- a/devtools/credits.pl
+++ b/devtools/credits.pl
@@ -536,7 +536,7 @@ begin_credits("Credits");
begin_section("AGI");
add_person("Stuart George", "darkfiber", "");
- add_person("Matthew Hoops", "clone2727", "");
+ add_person("Matthew Hoops", "clone2727", "(retired)");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Martin Kiewitz", "m_kiewitz", "");
add_person("Pawe&#322; Ko&#322;odziejski", "aquadran", "");
@@ -604,6 +604,7 @@ begin_credits("Credits");
begin_section("Drascula");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Pawe&#322; Ko&#322;odziejski", "aquadran", "");
+ add_person("Thierry Crozat", "criezy", "");
end_section();
begin_section("DreamWeb");
@@ -614,6 +615,11 @@ begin_credits("Credits");
add_person("Willem Jan Palenstijn", "wjp", "");
end_section();
+ begin_section("Gnap");
+ add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
+ add_person("Benjamin Haisch", "john_doe", "");
+ end_section();
+
begin_section("Gob");
add_person("Torbj&ouml;rn Andersson", "eriktorbjorn", "");
add_person("Arnaud Boutonn&eacute;", "Strangerke", "");
@@ -647,7 +653,7 @@ begin_credits("Credits");
end_section();
begin_section("Lastexpress");
- add_person("Matthew Hoops", "clone2727", "");
+ add_person("Matthew Hoops", "clone2727", "(retired)");
add_person("Jordi Vilalta Prat", "jvprat", "");
add_person("Julien Templier", "littleboy", "");
end_section();
@@ -669,7 +675,7 @@ begin_credits("Credits");
begin_section("Mohawk");
add_person("Bastien Bouclet", "bgk", "");
- add_person("Matthew Hoops", "clone2727", "");
+ add_person("Matthew Hoops", "clone2727", "(retired)");
add_person("Filippos Karapetis", "[md5]", "");
add_person("Alyssa Milburn", "fuzzie", "");
add_person("Eugene Sandulenko", "sev", "");
@@ -691,7 +697,7 @@ begin_credits("Credits");
end_section();
begin_section("Pegasus");
- add_person("Matthew Hoops", "clone2727", "");
+ add_person("Matthew Hoops", "clone2727", "(retired)");
end_section();
begin_section("Queen");
@@ -817,6 +823,7 @@ begin_credits("Credits");
begin_section("Android");
add_person("Andre Heider", "dhewg", "");
add_person("Angus Lees", "Gus", "");
+ add_person("Lubomyr Lisen", "", "");
end_section();
begin_section("Dreamcast");
@@ -845,6 +852,10 @@ begin_credits("Credits");
add_person("Tarek Soliman", "tsoliman", "");
end_section();
+ begin_section("Nintendo 3DS");
+ add_person("Thomas Edvalson", "Cruel", "");
+ end_section();
+
begin_section("Nintendo 64");
add_person("Fabio Battaglia", "Hkz", "");
end_section();
@@ -953,7 +964,7 @@ begin_credits("Credits");
begin_persons();
add_person("Thierry Crozat", "criezy", "Numerous contributions to documentation");
add_person("Joachim Eberhard", "joachimeberhard", "Numerous contributions to documentation (retired)");
- add_person("Matthew Hoops", "clone2727", "Wiki editor");
+ add_person("Matthew Hoops", "clone2727", "Numerous contributions to documentation (retired)");
end_persons();
end_section();
@@ -1007,6 +1018,7 @@ begin_credits("Credits");
begin_section("Mac OS X");
add_person("Max Horn", "Fingolfin", "(retired)");
add_person("Oystein Eftevaag", "vinterstum", "");
+ add_person("Thierry Crozat", "criezy", "");
end_section();
begin_section("Mandriva");
diff --git a/devtools/encode-macbinary.sh b/devtools/encode-macbinary.sh
new file mode 100755
index 0000000000..6635f7fcda
--- /dev/null
+++ b/devtools/encode-macbinary.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Iterates over current directory, encodes all files with
+# MacBinary but ensures that the dates are preserved
+
+for i in *
+do
+ macbinary encode "$i"
+ touch -r "$i" "$i.bin"
+ mv "$i.bin" "$i"
+done
diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index e9140f74f9..92754a27b4 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -50,25 +50,26 @@
# IFS=$OIFS
#
maniac Maniac Mansion
- 2d624d1b214f7faf0094daea65c6d1a6 -1 en 2gs Apple II - -
+ 2d624d1b214f7faf0094daea65c6d1a6 -1 en 2gs Apple II - -
2cb46375dd5cdfd023e2f07e0a21b530 -1 en C64 C64 Demo - Robert Crossfield
- eea4d9ac2fb6f145945a308e8866915b -1 en C64 C64 - -
- 439a7f4adf510489981ac52308e7d7a2 -1 de C64 C64 - -
+ eea4d9ac2fb6f145945a308e8866915b -1 en C64 C64 - -
+ 439a7f4adf510489981ac52308e7d7a2 -1 de C64 C64 - -
7f45ddd6dbfbf8f80c0c0efea4c295bc 1972 en DOS V1 V1 - Fingolfin
- 17f7296f63c78642724f057fd8e736a7 2082 gb NES NES -
- 91d5db93187fab54d823f73bd6441cb6 -1 us NES NES -
- 1c7e7db2cfab1ad62746ab680a634204 -1 fr NES NES -
- 3a5ec90d556d4920976c5578bfbfaf79 -1 de NES NES -
- b7d37d6b786b5a22deea3b038eca96ca -1 es NES NES -
- fa3cb1541f9d7cf99ccbae6249bc150c -1 it NES NES -
- 6b5a3fef241e90d4b2e77f1e222773ee -1 se NES NES -
+ 17f7296f63c78642724f057fd8e736a7 2082 gb NES NES -
+ 91d5db93187fab54d823f73bd6441cb6 -1 us NES NES -
+ 1c7e7db2cfab1ad62746ab680a634204 -1 fr NES NES -
+ 3a5ec90d556d4920976c5578bfbfaf79 -1 de NES NES -
+ b7d37d6b786b5a22deea3b038eca96ca -1 es NES NES -
+ fa3cb1541f9d7cf99ccbae6249bc150c -1 it NES NES -
+ 6b5a3fef241e90d4b2e77f1e222773ee -1 se NES NES -
e781230da44a44e2f0770edb2b3b3633 -1 en Amiga V2 V2 - dhewg, Andrea Petrucci
ce7733f185b838e248927c7ba1a04204 -1 fr Amiga V2 V2 - Tobias Fleischer
9bc548e179cdb0767009401c094d0895 -1 de Amiga V2 V2 - Norbert Lange
+ 3cf4b6ff78f735b671d8ccc2bc110b15 -1 es Amiga V2 V2 - vanfanel
a570381b028972d891052ee1e51dc011 1988 en Atari V2 V2 SS Andreas Bylund
0c331637580950aea2346e012ef2a868 1988 en Atari V2 V2 DS Petr Maruska
dd30a53035393baa5a5e222e716559af -1 fr Atari V2 V2 - Andreas Bylund
@@ -87,9 +88,9 @@ maniac Maniac Mansion
3a988de37118873ad129246b452909c0 1988 ru DOS V2 Demo V2 Demo non-interactive sev
zak Zak McKracken and the Alien Mindbenders
- 254fede2f15dbb32a23760d601b01816 -1 en C64 V1 - -
- 95be99181bd0f10fef4872c2d4a771cb -1 de C64 V1 - -
- aeec382acef62e122bf0d5b14581cfa4 -1 it C64 V1 - -
+ 254fede2f15dbb32a23760d601b01816 -1 en C64 V1 - -
+ 95be99181bd0f10fef4872c2d4a771cb -1 de C64 V1 - -
+ aeec382acef62e122bf0d5b14581cfa4 -1 it C64 V1 - -
7020931d5a2be0a49d68e7a1882363e4 1896 en DOS V1 V1 - Fingolfin
b23f7cd7c304d7dff08e92a96120d5b4 -1 en DOS V1 V1 alt? Andrea Petrucci
@@ -97,9 +98,9 @@ zak Zak McKracken and the Alien Mindbenders
91469353f7be1b122fa88d23480a1320 -1 fr Amiga V2 V2 - Tobias Fleischer
6027e9ca9c35746d95dee2068cec17e5 -1 de Amiga V2 V2 - Norbert Lange
27b3a4224ad63d5b04627595c1c1a025 -1 it Amiga V2 V2 - Andrea Petrucci
- d55eff37c2100f5065cde9de428621fa -1 en Atari V2 V2 -
+ d55eff37c2100f5065cde9de428621fa -1 en Atari V2 V2 -
613f64f78ea26c7353b2a5940eb61d6a -1 fr Atari V2 V2 - Andreas Bylund
- ff05c07990061d97647f059c48c1d05a -1 de Atari V2 V2 -
+ ff05c07990061d97647f059c48c1d05a -1 de Atari V2 V2 -
675d71151e9b5a968c8ce46d9fbf4cbf 1916 en DOS V2 V2 - Kirben
debe337f73d660e951ece7c1f1c81add -1 en DOS V2 V2 alt? Andrea Petrucci
52a4bae0746a11d7b1e8554e91a6645c -1 fr DOS V2 V2 - Andrea Petrucci
@@ -110,7 +111,7 @@ zak Zak McKracken and the Alien Mindbenders
75ba23fff4fd63fa446c02864f2a5a4b -1 it DOS V2 V2 alt? Antti Leimi, Andrea Petrucci
a77d0efbe786ea7f490c2021dbfa3f2f -1 ru DOS V2 V2 - sev
- 2d4536a56e01da4b02eb021e7770afa2 7520 en FM-TOWNS FM-TOWNS - -
+ 2d4536a56e01da4b02eb021e7770afa2 7520 en FM-TOWNS FM-TOWNS - -
1ca86e2cf9aaa2068738a1e5ba477e60 -1 jp FM-TOWNS FM-TOWNS - - Andrea Petrucci
8299d9b8a1b0e7b881bae7a9971dc5e2 1916 en Atari V2 Demo non-interactive Fingolfin
@@ -120,7 +121,7 @@ indy3 Indiana Jones and the Last Crusade
e689bdf67f98b1d760ce4487ec0e8d06 -1 fr Amiga EGA EGA - Gerald Vincent
330f631502e381a4e199a3f7cb483c20 -1 de Amiga EGA EGA - dhewg
df03ee021aa9b81d90cab9c26da07614 -1 it Amiga EGA EGA - Andrea Petrucci
- 62b8c16b6db226ba95aaa8be73f9885c -1 es Amiga EGA EGA -
+ 62b8c16b6db226ba95aaa8be73f9885c -1 es Amiga EGA EGA -
157367c3c21e0d03a0cba44361b4cf65 -1 en Atari No AdLib EGA - Andreas Bylund
0f9c7a76657f0840b8f7ccb5bffeb9f4 -1 fr Atari No AdLib EGA - Andreas Bylund
aaa7f36a253f277dd29dd1c051b0e4b9 -1 de Atari No AdLib EGA - Jimmy Kohl
@@ -130,7 +131,7 @@ indy3 Indiana Jones and the Last Crusade
66236cd1aec24e1d4aff4c4cc93b7e18 -1 fr DOS EGA EGA ?? v1.3, 25 Aug 89 Andrea Petrucci, Peter Eckerlein
89cfc425566003ff74b7dc7b3e6fd469 -1 fr DOS EGA EGA ?? v1.3, 25 Aug 89 Jorpho
69d70269fafc4445adbb0d223e4f9a3f 5361 en DOS EGA EGA v1.4, 11/07/89 (5.25\") Petr Maruska
- 56e8c37a0a08c3a7076f82417461a877 -1 en DOS EGA EGA v1.4, 7 Nov 89 (3.5\") Paulo Vicente
+ 56e8c37a0a08c3a7076f82417461a877 -1 en DOS EGA EGA v1.4, 7 Nov 89 (3.5\") Paulo Vicente
6f6ef668c608c7f534fea6e6d3878dde -1 de DOS EGA EGA v1.4 from 19 Oct 89 dhewg, Peter Eckerlein
eb700bb73ca1cc44a1ad5e4b1a4bdeaf 5361 de DOS EGA EGA PC-Spiele a.borque
d62d248c3df6ec177405e2cb23d923b2 -1 it DOS EGA EGA v1.4 from 25 Nov 89 Andrea Petrucci, Peter Eckerlein
@@ -143,7 +144,7 @@ indy3 Indiana Jones and the Last Crusade
a15d6e1e2c52bbd0ff7fa6b63ab7f796 680340 en Mac Steam Steam Steam Version Filippos Karapetis
399b217b0c8d65d0398076da486363a9 6295 de DOS VGA VGA VGA v1.02 from 7 Nov 91 Peter Eckerlein, Fingolfin
17b5d5e6af4ae89d62631641d66d5a05 -1 it DOS VGA VGA IBM 256 color v2.1 from 3 May 01 Andrea Petrucci, Peter Eckerlein
- 3cce1913a3bc586b51a75c3892ff18dd -1 ru DOS VGA VGA VGA
+ 3cce1913a3bc586b51a75c3892ff18dd -1 ru DOS VGA VGA VGA
04687cdf7f975a89d2474929f7b80946 7552 en FM-TOWNS FM-TOWNS - v1.00 1/23/91 Fingolfin
3a0c35f3c147b98a2bdf8d400cfc4ab5 -1 jp FM-TOWNS FM-TOWNS - - Paul Priest, Andrea Petrucci
@@ -155,8 +156,8 @@ loom Loom
39cb9dec16fa16f38d79acd80effb059 -1 All Amiga EGA EGA IT and FR Gerald Vincent (IT), Andrea Petrucci (FR)
2fe369ad70f52a8cf7ad6077ee64f81a -1 de Amiga EGA EGA - Norbert Lange
48b9f04b348bc5013327753f0d12a144 -1 es Amiga EGA EGA - VooD
- a0a7dea72003933b8b3f8b99b9f7ddeb -1 en Atari No AdLib EGA -
- 0e9b01430e31d9fcd94071d433bbc6bf -1 fr Atari No AdLib EGA -
+ a0a7dea72003933b8b3f8b99b9f7ddeb -1 en Atari No AdLib EGA -
+ 0e9b01430e31d9fcd94071d433bbc6bf -1 fr Atari No AdLib EGA -
c24c490373aeb48fbd54caa8e7ae376d -1 de Atari No AdLib EGA - Andreas Bylund
28ef68ee3ed76d7e2ee8ee13c15fbd5b 5748 en DOS EGA EGA v1.0 from 8 Mar 90 Peter Eckerlein, Fingolfin
73e5ab7dbb9a8061cc6d25df02dbd1e7 -1 en DOS EGA EGA v1.0 alt Andrea Petrucci
@@ -167,7 +168,7 @@ loom Loom
6f8a22bfa397be1f7ed4b74aba0e397e -1 fr DOS EGA EGA v1.2 26 Jun 90 Jorpho
470c45b636139bb40716daa1c7edaad0 -1 de DOS EGA EGA v1.2 Deutsch from 7 Jun 90 Peter Eckerlein
fa127d7c4bb47d05bb1c33ddcaa9f767 5748 de DOS EGA EGA v1.2 Deutsch from 7 Jun 90 Fingolfin
- 187d315f6b5168f68680dfe8c3d76a3e -1 he DOS EGA EGA -
+ 187d315f6b5168f68680dfe8c3d76a3e -1 he DOS EGA EGA -
c3df37df9d3b481b45f75283a9907c47 -1 it DOS EGA EGA - Andrea Petrucci
0be88565f734b1e9e77ccaaf3bb14b29 -1 es DOS EGA EGA v1.2 Espanol from 31 Aug 90 George Kormend
2a208ffbcd0e83e86f4356e6f64aa6e1 -1 es DOS EGA EGA v1.2 Espanol from 31 Aug 90 abnog, Andrea Petrucci, Peter Eckerlein
@@ -187,10 +188,10 @@ loom Loom
a00554c31d623fdb9fcb0f924b89b42b -1 en DOS EGA EGA Demo non-interactive Adrian C. Fruehwirth
monkey The Secret of Monkey Island
- c666a998af90d81db447eccba9f72c8d -1 en Atari No AdLib EGA -
+ c666a998af90d81db447eccba9f72c8d -1 en Atari No AdLib EGA -
9e5e0fb43bd22f4628719b7501adb717 -1 fr Atari No AdLib EGA - Andreas Bylund
927a764615c7fcdd72f591355e089d8c -1 de Atari No AdLib EGA - Joachim Eberhard
- 0a41311d462b6639fc45297b9044bf16 -1 es Atari No AdLib EGA -
+ 0a41311d462b6639fc45297b9044bf16 -1 es Atari No AdLib EGA -
49210e124e4c2b30f1290a9ef6306301 8357 en DOS EGA EGA 8 disk v1.0, 9/18/90 Fingolfin
1dd3c11ea4439adfe681e4e405b624e1 -1 fr DOS EGA EGA 8 disk Andrea Petrucci
@@ -210,7 +211,7 @@ monkey The Secret of Monkey Island
870d1e3c86bc50846d808d14a36b4e08 -1 es Amiga VGA VGA - Andreas Bylund
c7890e038806df2bb5c0c8c6f1986ea2 -1 en DOS VGA VGA 8 disk Andrea Petrucci
- 15e03ffbfeddb9c2aebc13dcb2a4a8f4 8357 en DOS VGA VGA 4 disk
+ 15e03ffbfeddb9c2aebc13dcb2a4a8f4 8357 en DOS VGA VGA 4 disk
08656dd9698ddf1023ba9bf8a195e37b -1 en DOS VGA VGA V1.1 crossbow777
d0b531227a27c6662018d2bd05aac52a 8357 de DOS VGA VGA 4 disk v1.1, 14.Feb.91 Fingolfin
66fd5ff9a810dfeb6d6bdada18221140 -1 it DOS VGA VGA 4 disk Andrea Petrucci
@@ -225,9 +226,9 @@ monkey The Secret of Monkey Island
da6269b18fcb08189c0aa9c95533cce2 8955 it DOS CD CD CD-ROM v2.3 Fingolfin, Andrej Sinicyn, Andrea Petrucci
f049e38c1f8302b5db6170f1872af89a 8955 es DOS CD CD CD-ROM v2.3 Fingolfin, Andrej Sinicyn, Andrea Petrucci
2ccd8891ce4d3f1a334d21bff6a88ca2 9455 en Mac CD - Mac v2.4 Fingolfin, Lars N&aelig;sbye Christensen
- b9ba19ce376efc69be78ef3baef8d2b9 -1 en Mac CD - alt? Grant Yeager
+ b9ba19ce376efc69be78ef3baef8d2b9 -1 en Mac CD - alt? Grant Yeager
- c13225cb1bbd3bc9fe578301696d8021 -1 en SEGA SEGA - -
+ c13225cb1bbd3bc9fe578301696d8021 -1 en SEGA SEGA - -
057c9b456dedcc4d71b991a3072a20b3 9465 jp SEGA SEGA - - GloKidd
8eb84cee9b429314c7f0bdcf560723eb 9925 en FM-TOWNS FM-TOWNS - - Paul Priest, Andrea Petrucci
@@ -236,6 +237,7 @@ monkey The Secret of Monkey Island
71523b539491527d9860f4407faf0411 7607 en DOS Demo EGA Demo - Fingolfin
771bc18ec6f93837b839c992b211904b -1 de DOS Demo EGA Demo - khalek
54a936ad06161ff7bfefcb96200f7bff 7617 en Amiga VGA VGA Demo - khalek
+ c0c9de81fb965e6cbe77f6e5631ca705 9135 en DOS SE Talkie Unofficial SE Talkie v1.02 rootfather
pass Passport to Adventure
e6cd81b25ab1453a8a6d3482118c391e 7857 en DOS - - v1.0 9/14/90 Fingolfin
@@ -255,7 +257,7 @@ monkey2 Monkey Island 2: LeChuck's Revenge
da669b20271b85182e9c17a2a37ea02e -1 de Amiga - - - Andreas Bylund, Norbert Lange
11ddf1fde76e3156eb3a38da213f484e -1 it Amiga - - - Andrea Petrucci
6ea966b4d660c870b9ee790d1fbfc535 -1 es Amiga - - - Andreas Bylund
- 3686cf8f89e102ececf4366e1d2c8126 11135 en DOS - - -
+ 3686cf8f89e102ececf4366e1d2c8126 11135 en DOS - - -
8e4ee4db46954bfe2912e259a16fad82 -1 fr DOS - - - Nicolas Sauz&egrave;de, Andrea Petrucci
6886e5d08cee329b1f2e743ae2e3ceed 11135 de DOS - - v1.0D 17Feb92 Fingolfin
69ea626f1f87eecb78ea0d6c6b983a1d -1 it DOS - - - Andrea Petrucci
@@ -268,6 +270,7 @@ monkey2 Monkey Island 2: LeChuck's Revenge
430bc518017b6fac046f58bab6baad5d -1 jp FM-TOWNS FM-TOWNS - - Antti Leimi, Andrea Petrucci
387a544b8b10b26912d8413bab63a853 -1 en DOS - Demo non-interactive khalek
+ f4d20ab4ce19743a646cb48bd93aee72 10835 en DOS SE Talkie Unofficial SE Talkie v0.2 rootfather
atlantis Indiana Jones and the Fate of Atlantis
3a03dab514e4038df192d8a8de469788 -1 en Amiga Floppy Floppy - dhewg
@@ -295,14 +298,14 @@ atlantis Indiana Jones and the Fate of Atlantis
c7be10f775404fd9785a8b92a06d240c 12030 en FM-TOWNS FM-TOWNS - - dhewg, Andrea Petrucci
4d34042713958b971cb139fba4658586 -1 jp FM-TOWNS FM-TOWNS - - Andrea Petrucci
- 035deab53b47bc43abc763560d0f8d4b -1 en DOS Floppy Demo -
+ 035deab53b47bc43abc763560d0f8d4b -1 en DOS Floppy Demo -
98744fe66ff730e8c2b3b1f58803ab0b -1 en DOS Floppy Demo - Simon Krumrein, sev
12cdc256eae5a461bcc9a49975999841 -1 en DOS Floppy Demo - Paulo Vicente
- 99b6f822b0b2612415407865438697d6 -1 en DOS - Demo non-interactive
+ 99b6f822b0b2612415407865438697d6 -1 en DOS - Demo non-interactive
28d24a33448fab6795850bc9f159a4a2 11170 jp FM-TOWNS FM-TOWNS Demo non-interactive khalek, Fingolfin
tentacle Day of the Tentacle
- acad97ab1c6fc2a5b2d98abf6db4a190 -1 en All? Floppy Floppy Version A ?
+ acad97ab1c6fc2a5b2d98abf6db4a190 -1 en All? Floppy Floppy Version A ?
2723fea3dae0cb47768c424b145ae0e7 7932 en DOS Floppy Floppy Version B ? Andrej Sinicyn, Andrea Petrucci, Fingolfin
f0ccc12a8704bf57706b42a37f877128 -1 en DOS Floppy Floppy 1.6 Paulo Vicente
92b078d9d6d9d751da9c26b8b3075779 -1 fr DOS Floppy Floppy - Nicolas Sauz&egrave;de, Andrea Petrucci
@@ -338,11 +341,11 @@ samnmax Sam &amp; Max Hit the Road
0fb73eddfcf584c02ba097984df131ba 9080 de All? - CD - Fingolfin
0f6f2e716ba896a44e5059bba1de7ca9 -1 it All? - CD - Andrea Petrucci
4ba7fb331296c283e73d8f5b2096e551 -1 es All? - CD - Andrea Petrucci
- d43352a805d78b5f4936c6d7779bf575 -1 ru DOS - CD -
+ d43352a805d78b5f4936c6d7779bf575 -1 ru DOS - CD -
166553538ff320c69edafeee29525419 199195304 en Mac - CD Mac bundle Joachim Eberhard
3a5d13675e9a23aedac0bac7730f0ac1 228446581 fr Mac - CD Mac bundle ThierryFR, Thierry Crozat
- c3196c5349e53e387aaff1533d95e53a -1 en DOS Floppy Demo -
+ c3196c5349e53e387aaff1533d95e53a -1 en DOS Floppy Demo -
0e4c5d54a0ad4b26132e78b5ea76642a 6485 en DOS Floppy Demo WIP Fingolfin
d9d0dd93d16ab4dec55cabc2b86bbd17 6478 en DOS - Demo non-interactive Fingolfin
cc8ba2b0df2f9c450bcf055fe2711979 7485 de DOS Floppy Demo - Simon Krumrein, sev, Fingolfin
@@ -358,12 +361,12 @@ ft Full Throttle
55518cd73cf9c6d23ea29c51ee06bdfe -1 it All? - - - delfino
55e4cc866ff9046824e1c638ba2b8c7f -1 ru All? - Akella - sev
291fb06071e65897f755846611f5ad40 19697 ru All? - 7-Wolf - sev
- e72bb4c2b613db2cf50f89ff6350e70a -1 es All? - - -
+ e72bb4c2b613db2cf50f89ff6350e70a -1 es All? - - -
fe381e45117878b1e942cb876b050fd6 513243679 en Mac - - Mac bundle Fingolfin
04401d747f1a2c1c4b388daff71ed378 535405461 de Mac - - Mac bundle Fingolfin
403d2ec4d60d3cdae925e6cbf67716d6 489436643 fr Mac - - Mac bundle Thierry Crozat
- 32a433dea56b86a55b59e4ff7d755711 -1 en DOS Demo Demo -
+ 32a433dea56b86a55b59e4ff7d755711 -1 en DOS Demo Demo -
9d7b67be003fea60be4dcbd193611936 11164 en Mac Demo Demo - Fingolfin
9b7452b5cd6d3ffb2b2f5118010af84f 116463537 en Mac Demo Demo Mac bundle Fingolfin, Joachim Eberhard
@@ -381,7 +384,7 @@ dig The Dig
comi The Curse of Monkey Island
fe60d6b5ff51b0553ac59963123b5777 76791 All Windows - - - Fingolfin
- 861e59ed72a1cd0e6d454f7ee7e2bf3d -1 ru Windows - - -
+ 861e59ed72a1cd0e6d454f7ee7e2bf3d -1 ru Windows - - -
8fec68383202d38c0d25e9e3b757c5df 18041 All Windows Demo Demo - Fingolfin
@@ -764,7 +767,7 @@ puttmoon Putt-Putt Goes to the Moon
9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek
3c4c471342bd95505a42334367d8f127 12161 ru Windows HE 70 - - sev
- aa6a91b7f6f119d1b7b1f2a4c9e24d59 6233 en DOS - Demo -
+ aa6a91b7f6f119d1b7b1f2a4c9e24d59 6233 en DOS - Demo -
4af4a6b248103c1fe9edef619677f540 -1 en Mac - Demo - khalek
9c143c5905055d5df7a0f014ab379aee -1 en Windows HE 70 Demo - khalek
@@ -792,7 +795,7 @@ puttputt Putt-Putt Joins the Parade
684732efb5799c0f78804c99d8de9aba -1 en Mac HE 62 - - khalek
6a30a07f353a75cdc602db27d73e1b42 -1 en Windows HE 70 - - khalek
- 31aa57f460a3d12429f0552a46a90b39 6150 en DOS Demo Demo -
+ 31aa57f460a3d12429f0552a46a90b39 6150 en DOS Demo Demo -
f40a7f495f59188ca57a9d1d50301bb6 -1 en Mac HE 60 Demo - khalek
37ff1b308999c4cca7319edfcc1280a0 8269 en Windows HE 70 Demo - khalek
@@ -834,7 +837,7 @@ PuttTime Putt-Putt Travels Through Time
59d5cfcc5e672a6e07baae01328b918b -1 fr All HE 90 Demo - Kirben
fbb697d89d2beca87360a145f467bdae -1 de All HE 90 Demo - Joachim Eberhard
6b19d0e25cbf720d05822379b8b90ed9 -1 nl All HE 90 Demo - adutchguy
- 0a6d7b81b850ed4a77811c60c9b5c555 18458 us Windows HE 99 Mini Game - eriktorbjorn
+ 0a6d7b81b850ed4a77811c60c9b5c555 18458 us Windows HE 99 Mini Game - eriktorbjorn
a71014c53a6d18c66ef2ea0ee42328e9 18458 nl Windows HE 99 Mini Game - Ben Castricum
8dd4d590685c19bf651b5016e749ead2 18458 fr Windows HE 99 Mini Game - Ben Castricum
aef415cc5dc063e3668359c2657169f3 18458 de Windows HE 99 Mini Game - Ben Castricum
@@ -859,16 +862,16 @@ dog Putt-Putt and Pep's Dog on a Stick
d4b8ee426b1afd3e53bc0cf020418cf6 -1 en Windows HE 99 - - sev
activity Putt-Putt & Fatty Bear's Activity Pack
- 2c04aacffb8428f30ccf4f734fbe3adc -1 en DOS - - - Kirben
+ 2c04aacffb8428f30ccf4f734fbe3adc -1 en DOS - - - Kirben
0e96ab45a4eb72acc1b46813976589fd -1 en Mac - - - Kirben
- b628506f7def772e40de0aa5440fb8e1 -1 en Windows HE 70 - - Kirben
+ b628506f7def772e40de0aa5440fb8e1 -1 en Windows HE 70 - - Kirben
funpack Putt-Putt's Fun Pack
8afb3cf9f95abf208358e984f0c9e738 -1 en 3DO - - - sev
e95cf980719c0be078fb68a67af97b4a -1 jp 3DO - - - clone2727
3d219e7546039543307b55a91282bf18 -1 en DOS - - - iziku
46b53fd430adcfbed791b48a0d4b079f -1 en DOS - - - khalek
- 90a329d8ad5b7ce0690429e98cfbb32f -1 he DOS - - -
+ 90a329d8ad5b7ce0690429e98cfbb32f -1 he DOS - - -
PuttsFunShop Putt-Putt's One-Stop Fun Shop
5262a27afcaee04e5c4900220bd463e7 -1 us All - - - Kirben
@@ -922,7 +925,7 @@ spyozon SPY Fox 3: Operation Ozone
10d8e66cd11049ce64815ebb9fd76eb3 -1 fr All - - - gist974, ThierryFR
96a3069a3c63caa7329588ce1fef41ee -1 ru All - - - sev
7015b059ab72cff3a0ef9fb4d5e9889d -1 de Windows - - - andy482
- be39a5d4db60e8aa736b9086778cb45c -1 gb Windows - - -
+ be39a5d4db60e8aa736b9086778cb45c -1 gb Windows - - -
ebd0b2c8a387f18887282afe6cad894a 15317 us All - Demo - Kirben
a99c39ba65b6086be28aef576da69595 -1 fr Windows - Demo - Mevi
diff --git a/devtools/skycpt/COMPACT.TXT b/devtools/skycpt/COMPACT.TXT
index af22e129cf..4f8f5b97d9 100644
--- a/devtools/skycpt/COMPACT.TXT
+++ b/devtools/skycpt/COMPACT.TXT
@@ -2741,7 +2741,7 @@ SECTION::MAINLISTS
0000::NULL
40E6::sc38_phone_talk
40F4::sc32_garden_talk
- 40DF::sc31_guard_talk
+ 40DF::sc31_guard_talk2
4145::barman_talk
4168::sc36_col_talk2
4169::sc36_gal_talk
diff --git a/devtools/skycpt/README b/devtools/skycpt/README
index 4b303cb0e9..ec7828f35c 100644
--- a/devtools/skycpt/README
+++ b/devtools/skycpt/README
@@ -16,8 +16,8 @@ This program was only included in ScummVM's source tree because the Debian licen
forces us to.
Instead download the file from http://www.scummvm.org/
Also, please be aware that if you create your own CPT file (if it isn't exactly the same as the
-one we offer for download at www.scummvm.org), it will be incompatible and the savegames produced
-using the file will be incompatible with ScummVM using the normal CPT file.
+one we offer for download at www.scummvm.org), it will be incompatible and the saved games
+produced using the file will be incompatible with ScummVM using the normal CPT file.
The incompatibility will not be detected by ScummVM, it will most probably simply crash.
If you still want to waste your time by creating this file:
diff --git a/devtools/update-version.pl b/devtools/update-version.pl
index 337bad3e6c..3b5f892c3f 100755
--- a/devtools/update-version.pl
+++ b/devtools/update-version.pl
@@ -37,6 +37,7 @@ my @subs_files = qw(
dists/scummvm.rc
dists/slackware/scummvm.SlackBuild
dists/macosx/Info.plist
+ dists/macosx/dockplugin/Info.plist
dists/iphone/Info.plist
dists/ios7/Info.plist
dists/irix/scummvm.spec
diff --git a/dists/android/AndroidManifest.xml b/dists/android/AndroidManifest.xml
index d605d9b3cc..c091039266 100644
--- a/dists/android/AndroidManifest.xml
+++ b/dists/android/AndroidManifest.xml
@@ -15,6 +15,7 @@
<application
android:label="@string/app_name"
android:description="@string/app_desc"
+ android:isGame="true"
android:icon="@drawable/scummvm">
<activity android:name=".ScummVMActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -27,19 +28,25 @@
<category android:name="tv.ouya.intent.category.GAME"/>
</intent-filter>
</activity>
+ <activity android:name=".ScummVMActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:banner="@drawable/leanback_icon">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <!-- Always needs some sort of qwerty keyboard.
- Can work with a D-pad / trackball -->
- <uses-configuration android:reqFiveWayNav="true"
- android:reqKeyboardType="qwerty"/>
+ <uses-feature android:name="android.hardware.screen.landscape"
+ android:required="false" />
+
+ <uses-feature android:name="android.hardware.touchscreen"
+ android:required="false" />
- <!-- .. or touchscreen -->
- <uses-configuration android:reqTouchScreen="finger"
- android:reqKeyboardType="qwerty"/>
+ <uses-feature android:name="android.software.leanback"
+ android:required="false" />
- <uses-configuration android:reqTouchScreen="stylus"
- android:reqKeyboardType="qwerty"/>
</manifest>
diff --git a/dists/android/AndroidManifest.xml.in b/dists/android/AndroidManifest.xml.in
index d90e282e3d..7eaece9d1f 100644
--- a/dists/android/AndroidManifest.xml.in
+++ b/dists/android/AndroidManifest.xml.in
@@ -15,6 +15,7 @@
<application
android:label="@string/app_name"
android:description="@string/app_desc"
+ android:isGame="true"
android:icon="@drawable/scummvm">
<activity android:name=".ScummVMActivity"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
@@ -27,19 +28,25 @@
<category android:name="tv.ouya.intent.category.GAME"/>
</intent-filter>
</activity>
+ <activity android:name=".ScummVMActivity"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:banner="@drawable/leanback_icon">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <!-- Always needs some sort of qwerty keyboard.
- Can work with a D-pad / trackball -->
- <uses-configuration android:reqFiveWayNav="true"
- android:reqKeyboardType="qwerty"/>
+ <uses-feature android:name="android.hardware.screen.landscape"
+ android:required="false" />
+
+ <uses-feature android:name="android.hardware.touchscreen"
+ android:required="false" />
- <!-- .. or touchscreen -->
- <uses-configuration android:reqTouchScreen="finger"
- android:reqKeyboardType="qwerty"/>
+ <uses-feature android:name="android.software.leanback"
+ android:required="false" />
- <uses-configuration android:reqTouchScreen="stylus"
- android:reqKeyboardType="qwerty"/>
</manifest>
diff --git a/dists/android/res/drawable-xhdpi/leanback_icon.png b/dists/android/res/drawable-xhdpi/leanback_icon.png
new file mode 100644
index 0000000000..28a7196b7f
--- /dev/null
+++ b/dists/android/res/drawable-xhdpi/leanback_icon.png
Binary files differ
diff --git a/dists/androidsdl/scummvm/AndroidAppSettings.cfg b/dists/androidsdl/scummvm/AndroidAppSettings.cfg
new file mode 100644
index 0000000000..d9f05ad2f4
--- /dev/null
+++ b/dists/androidsdl/scummvm/AndroidAppSettings.cfg
@@ -0,0 +1,230 @@
+# The application settings for Android libSDL port
+
+AppSettingVersion=19
+
+# libSDL version to use (1.2 or 1.3, specify 1.3 for SDL2)
+LibSdlVersion=1.2
+
+# Specify application name (e.x. My Application)
+AppName="ScummVM-SDL"
+
+# Specify reversed site name of application (e.x. com.mysite.myapp)
+AppFullName=org.scummvm.sdl
+
+# Specify screen orientation: (v)ertical/(p)ortrait or (h)orizontal/(l)andscape
+ScreenOrientation=h
+
+# Do not allow device to sleep when the application is in foreground, set this for video players or apps which use accelerometer
+InhibitSuspend=y
+
+# Specify path to download application data in zip archive in the form 'Description|URL|MirrorURL^Description2|URL2|MirrorURL2^...'
+# If you'll start Description with '!' symbol it will be enabled by default, other downloads should be selected by user from startup config menu
+# If the URL in in the form ':dir/file.dat:http://URL/' it will be downloaded as binary BLOB to the application dir and not unzipped
+# If the URL does not contain 'http://' it is treated as file from 'project/jni/application/src/AndroidData' dir -
+# these files are put inside .apk package by build system
+# Also please avoid 'https://' URLs, many Android devices do not have trust certificates and will fail to connect to SF.net over HTTPS
+AppDataDownloadUrl="!!App data|scummvm190-git-appdata.zip"
+
+# Video color depth - 16 BPP is the fastest and supported for all modes, 24 bpp is supported only
+# with SwVideoMode=y, SDL_OPENGL mode supports everything. (16)/(24)/(32)
+VideoDepthBpp=32
+
+# Enable OpenGL depth buffer (needed only for 3-d applications, small speed decrease) (y) or (n)
+NeedDepthBuffer=y
+
+# Enable OpenGL stencil buffer (needed only for 3-d applications, small speed decrease) (y) or (n)
+NeedStencilBuffer=y
+
+# Try to use GLES 2.x context - will revert to GLES 1.X if unsupported by device
+# you need this option only if you're developing 3-d app (y) or (n)
+NeedGles2=n
+
+# Application uses software video buffer - you're calling SDL_SetVideoMode() without SDL_HWSURFACE and without SDL_OPENGL,
+# this will allow small speed optimization. Enable this even when you're using SDL_HWSURFACE. (y) or (n)
+SwVideoMode=y
+
+# Application video output will be resized to fit into native device screen (y)/(n)
+SdlVideoResize=y
+
+# Application resizing will keep 4:3 aspect ratio, with black bars at sides (y)/(n)
+SdlVideoResizeKeepAspect=n
+
+# Application does not call SDL_Flip() or SDL_UpdateRects() appropriately, or draws from non-main thread -
+# enabling the compatibility mode will force screen update every 100 milliseconds, which is laggy and inefficient (y) or (n)
+CompatibilityHacks=n
+
+# Application initializes SDL audio/video inside static constructors (which is bad, you won't be able to run ndk-gdb) (y)/(n)
+CompatibilityHacksStaticInit=n
+
+# On-screen Android soft text input emulates hardware keyboard, this will only work with Hackers Keyboard app (y)/(n)
+CompatibilityHacksTextInputEmulatesHwKeyboard=y
+TextInputKeyboard=1
+
+# Hack for broken devices: prevent audio chopping, by sleeping a bit after pushing each audio chunk (y)/(n)
+CompatibilityHacksPreventAudioChopping=n
+
+# Hack for broken apps: application ignores audio buffer size returned by SDL (y)/(n)
+CompatibilityHacksAppIgnoresAudioBufferSize=n
+
+# Hack for VCMI: preload additional shared libraries before aplication start
+CompatibilityHacksAdditionalPreloadedSharedLibraries=""
+
+# Hack for Free Heroes 2, which redraws the screen inside SDL_PumpEvents(): slow and compatible SDL event queue -
+# do not use it with accelerometer/gyroscope, or your app may freeze at random (y)/(n)
+CompatibilityHacksSlowCompatibleEventQueue=n
+
+# Save and restore OpenGL state when drawing on-screen keyboard for apps that use SDL_OPENGL
+CompatibilityHacksTouchscreenKeyboardSaveRestoreOpenGLState=y
+
+# Application uses mouse (y) or (n), this will show mouse emulation dialog to the user
+AppUsesMouse=y
+
+# Application needs two-button mouse, will also enable advanced point-and-click features (y) or (n)
+AppNeedsTwoButtonMouse=y
+
+# Show SDL mouse cursor, for applications that do not draw cursor at all (y) or (n)
+ShowMouseCursor=n
+
+# Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n)
+ForceRelativeMouseMode=n
+
+# Application needs arrow keys (y) or (n), will show on-screen dpad/joystick (y) or (n)
+AppNeedsArrowKeys=n
+
+# Application needs text input (y) or (n), enables button for text input on screen
+AppNeedsTextInput=y
+
+# Application uses joystick (y) or (n), the on-screen DPAD will be used as joystick 0 axes 0-1
+AppUsesJoystick=n
+
+# Application uses second on-screen joystick, as SDL joystick 0 axes 2-3 (y)/(n)
+AppUsesSecondJoystick=n
+
+# Application uses accelerometer (y) or (n), the accelerometer will be used as joystick 1 axes 0-1 and 5-7
+AppUsesAccelerometer=n
+
+# Application uses gyroscope (y) or (n), the gyroscope will be used as joystick 1 axes 2-4
+AppUsesGyroscope=n
+
+# Application uses multitouch (y) or (n), multitouch events are passed as SDL_JOYBALLMOTION events for the joystick 0
+AppUsesMultitouch=y
+
+# Application records audio (it will use any available source, such a s microphone)
+# API is defined in file SDL_android.h: int SDL_ANDROID_OpenAudioRecording(SDL_AudioSpec *spec); void SDL_ANDROID_CloseAudioRecording(void);
+# This option will add additional permission to Android manifest (y)/(n)
+AppRecordsAudio=n
+
+# Application implements Android-specific routines to put to background, and will not draw anything to screen
+# between SDL_ACTIVEEVENT lost / gained notifications - you should check for them
+# rigth after SDL_Flip(), if (n) then SDL_Flip() will block till app in background (y) or (n)
+# This option is reported to be buggy, sometimes failing to restore video state
+NonBlockingSwapBuffers=n
+
+# Redefine common hardware keys to SDL keysyms
+# BACK hardware key is available on all devices, MENU is available on pre-ICS devices, other keys may be absent
+# SEARCH and CALL by default return same keycode as DPAD_CENTER - one of those keys is available on most devices
+# Use word NO_REMAP if you want to preserve native functionality for certain key (volume keys are 3-rd and 4-th)
+# Keys: TOUCHSCREEN (works only when AppUsesMouse=n), DPAD_CENTER/SEARCH, VOLUMEUP, VOLUMEDOWN, MENU, BACK, CAMERA
+RedefinedKeys="SPACE RETURN NO_REMAP NO_REMAP ESCAPE LCTRL F7 F4 F2 MOUSE_LEFT"
+
+# Number of virtual keyboard keys (currently 6 is maximum)
+AppTouchscreenKeyboardKeysAmount=0
+
+# Number of virtual keyboard keys that support autofire (currently 2 is maximum)
+AppTouchscreenKeyboardKeysAmountAutoFire=0
+
+# Redefine on-screen keyboard keys to SDL keysyms - 6 keyboard keys + 4 multitouch gestures (zoom in/out and rotate left/right)
+RedefinedKeysScreenKb="MOUSE_RIGHT F7 LCTRL"
+
+# Names for on-screen keyboard keys, such as Fire, Jump, Run etc, separated by spaces, they are used in SDL config menu
+RedefinedKeysScreenKbNames="MOUSE_RIGHT F7 LCTRL"
+
+# On-screen keys theme
+# 0 = Ultimate Droid by Sean Stieber (green, with gamepad joystick)
+# 1 = Simple Theme by Beholder (white, with gamepad joystick)
+# 2 = Sun by Sirea (yellow, with round joystick)
+# 3 = Keen by Gerstrong (multicolor, with round joystick)
+TouchscreenKeysTheme=1
+
+# Redefine gamepad keys to SDL keysyms, button order is:
+# A B X Y L1 R1 L2 R2 LThumb RThumb
+RedefinedKeysGamepad="MOUSE_RIGHT F7 LCTRL ESCAPE F5 SPACE RETURN MOUSE_LEFT"
+
+# How long to show startup menu button, in msec, 0 to disable startup menu
+StartupMenuButtonTimeout=3000
+
+# Menu items to hide from startup menu, available menu items:
+# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout
+HiddenMenuOptions='SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMouse.DisplaySizeConfig'
+
+# Menu items to show at startup - this is Java code snippet, leave empty for default
+# new SettingsMenuMisc.ShowReadme(), (AppUsesMouse \&\& \! ForceRelativeMouseMode \? new SettingsMenuMouse.DisplaySizeConfig(true) : new SettingsMenu.DummyMenu()), new SettingsMenuMisc.OptionalDownloadConfig(true), new SettingsMenuMisc.GyroscopeCalibration()
+# Available menu items:
+# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout
+FirstStartMenuOptions=''
+
+# Enable multi-ABI binary, with hardware FPU support - it will also work on old devices,
+# but .apk size is 2x bigger (y) / (n) / (x86) / (all)
+MultiABI="armeabi"
+
+# Minimum amount of RAM application requires, in Mb, SDL will print warning to user if it's lower
+AppMinimumRAM=256
+
+# Application version code (integer)
+AppVersionCode=@ANDROID_VERSIONCODE@
+
+# Application user-visible version name (string)
+AppVersionName="1.9.0git"
+
+# Reset SDL config when updating application to the new version (y) / (n)
+ResetSdlConfigForThisVersion=y
+
+# Delete application data files when upgrading (specify file/dir paths separated by spaces)
+DeleteFilesOnUpgrade="%"
+
+# Optional shared libraries to compile - removing some of them will save space
+# MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed
+# Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2
+CompiledLibraries="mad vorbis flac ogg jpeg png theora freetype faad"
+
+# Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n)
+CustomBuildScript=y
+
+# Aditional CFLAGS for application
+AppCflags=''
+
+# Additional LDFLAGS for application
+AppLdflags=''
+
+# If application has headers with the same name as system headers, this option tries to fix compiler flags to make it compilable
+AppOverlapsSystemHeaders=
+
+# Build only following subdirs (empty will build all dirs, ignored with custom script)
+AppSubdirsBuild=''
+
+# Exclude these files from build
+AppBuildExclude=''
+
+# Application command line parameters, including app name as 0-th param
+AppCmdline=''
+
+# Here you may type readme text, which will be shown during startup. Format is:
+# Text in English, use \\\\n to separate lines^de:Text in Deutsch^ru:Text in Russian, and so on (that's four backslashes, nice isn't it?)
+ReadmeText='^You may press "Home" now - the data will be downloaded in background'
+
+# Screen size is used by Google Play to prevent an app to be installed on devices with smaller screens
+# Minimum screen size that application supports: (s)mall / (m)edium / (l)arge
+MinimumScreenSize=s
+
+# Your AdMob Publisher ID, (n) if you don't want advertisements
+AdmobPublisherId=n
+
+# Your AdMob test device ID, to receive a test ad
+AdmobTestDeviceId=
+
+# Your AdMob banner size (BANNER/IAB_BANNER/IAB_LEADERBOARD/IAB_MRECT/IAB_WIDE_SKYSCRAPER/SMART_BANNER)
+AdmobBannerSize=
+
+UseGlshim=n
+
+AccessSdCard=y
diff --git a/dists/androidsdl/scummvm/AndroidAppSettings.cfg.in b/dists/androidsdl/scummvm/AndroidAppSettings.cfg.in
new file mode 100644
index 0000000000..bb437d2a7d
--- /dev/null
+++ b/dists/androidsdl/scummvm/AndroidAppSettings.cfg.in
@@ -0,0 +1,230 @@
+# The application settings for Android libSDL port
+
+AppSettingVersion=19
+
+# libSDL version to use (1.2 or 1.3, specify 1.3 for SDL2)
+LibSdlVersion=1.2
+
+# Specify application name (e.x. My Application)
+AppName="ScummVM-SDL"
+
+# Specify reversed site name of application (e.x. com.mysite.myapp)
+AppFullName=org.scummvm.sdl
+
+# Specify screen orientation: (v)ertical/(p)ortrait or (h)orizontal/(l)andscape
+ScreenOrientation=h
+
+# Do not allow device to sleep when the application is in foreground, set this for video players or apps which use accelerometer
+InhibitSuspend=y
+
+# Specify path to download application data in zip archive in the form 'Description|URL|MirrorURL^Description2|URL2|MirrorURL2^...'
+# If you'll start Description with '!' symbol it will be enabled by default, other downloads should be selected by user from startup config menu
+# If the URL in in the form ':dir/file.dat:http://URL/' it will be downloaded as binary BLOB to the application dir and not unzipped
+# If the URL does not contain 'http://' it is treated as file from 'project/jni/application/src/AndroidData' dir -
+# these files are put inside .apk package by build system
+# Also please avoid 'https://' URLs, many Android devices do not have trust certificates and will fail to connect to SF.net over HTTPS
+AppDataDownloadUrl="!!App data|scummvm190-git-appdata.zip"
+
+# Video color depth - 16 BPP is the fastest and supported for all modes, 24 bpp is supported only
+# with SwVideoMode=y, SDL_OPENGL mode supports everything. (16)/(24)/(32)
+VideoDepthBpp=32
+
+# Enable OpenGL depth buffer (needed only for 3-d applications, small speed decrease) (y) or (n)
+NeedDepthBuffer=y
+
+# Enable OpenGL stencil buffer (needed only for 3-d applications, small speed decrease) (y) or (n)
+NeedStencilBuffer=y
+
+# Try to use GLES 2.x context - will revert to GLES 1.X if unsupported by device
+# you need this option only if you're developing 3-d app (y) or (n)
+NeedGles2=n
+
+# Application uses software video buffer - you're calling SDL_SetVideoMode() without SDL_HWSURFACE and without SDL_OPENGL,
+# this will allow small speed optimization. Enable this even when you're using SDL_HWSURFACE. (y) or (n)
+SwVideoMode=n
+
+# Application video output will be resized to fit into native device screen (y)/(n)
+SdlVideoResize=y
+
+# Application resizing will keep 4:3 aspect ratio, with black bars at sides (y)/(n)
+SdlVideoResizeKeepAspect=n
+
+# Application does not call SDL_Flip() or SDL_UpdateRects() appropriately, or draws from non-main thread -
+# enabling the compatibility mode will force screen update every 100 milliseconds, which is laggy and inefficient (y) or (n)
+CompatibilityHacks=n
+
+# Application initializes SDL audio/video inside static constructors (which is bad, you won't be able to run ndk-gdb) (y)/(n)
+CompatibilityHacksStaticInit=n
+
+# On-screen Android soft text input emulates hardware keyboard, this will only work with Hackers Keyboard app (y)/(n)
+CompatibilityHacksTextInputEmulatesHwKeyboard=y
+TextInputKeyboard=1
+
+# Hack for broken devices: prevent audio chopping, by sleeping a bit after pushing each audio chunk (y)/(n)
+CompatibilityHacksPreventAudioChopping=n
+
+# Hack for broken apps: application ignores audio buffer size returned by SDL (y)/(n)
+CompatibilityHacksAppIgnoresAudioBufferSize=n
+
+# Hack for VCMI: preload additional shared libraries before aplication start
+CompatibilityHacksAdditionalPreloadedSharedLibraries=""
+
+# Hack for Free Heroes 2, which redraws the screen inside SDL_PumpEvents(): slow and compatible SDL event queue -
+# do not use it with accelerometer/gyroscope, or your app may freeze at random (y)/(n)
+CompatibilityHacksSlowCompatibleEventQueue=n
+
+# Save and restore OpenGL state when drawing on-screen keyboard for apps that use SDL_OPENGL
+CompatibilityHacksTouchscreenKeyboardSaveRestoreOpenGLState=y
+
+# Application uses mouse (y) or (n), this will show mouse emulation dialog to the user
+AppUsesMouse=y
+
+# Application needs two-button mouse, will also enable advanced point-and-click features (y) or (n)
+AppNeedsTwoButtonMouse=y
+
+# Show SDL mouse cursor, for applications that do not draw cursor at all (y) or (n)
+ShowMouseCursor=n
+
+# Force relative (laptop) mouse movement mode, useful when both on-screen keyboard and mouse are needed (y) or (n)
+ForceRelativeMouseMode=n
+
+# Application needs arrow keys (y) or (n), will show on-screen dpad/joystick (y) or (n)
+AppNeedsArrowKeys=n
+
+# Application needs text input (y) or (n), enables button for text input on screen
+AppNeedsTextInput=y
+
+# Application uses joystick (y) or (n), the on-screen DPAD will be used as joystick 0 axes 0-1
+AppUsesJoystick=n
+
+# Application uses second on-screen joystick, as SDL joystick 0 axes 2-3 (y)/(n)
+AppUsesSecondJoystick=n
+
+# Application uses accelerometer (y) or (n), the accelerometer will be used as joystick 1 axes 0-1 and 5-7
+AppUsesAccelerometer=n
+
+# Application uses gyroscope (y) or (n), the gyroscope will be used as joystick 1 axes 2-4
+AppUsesGyroscope=n
+
+# Application uses multitouch (y) or (n), multitouch events are passed as SDL_JOYBALLMOTION events for the joystick 0
+AppUsesMultitouch=y
+
+# Application records audio (it will use any available source, such a s microphone)
+# API is defined in file SDL_android.h: int SDL_ANDROID_OpenAudioRecording(SDL_AudioSpec *spec); void SDL_ANDROID_CloseAudioRecording(void);
+# This option will add additional permission to Android manifest (y)/(n)
+AppRecordsAudio=n
+
+# Application implements Android-specific routines to put to background, and will not draw anything to screen
+# between SDL_ACTIVEEVENT lost / gained notifications - you should check for them
+# rigth after SDL_Flip(), if (n) then SDL_Flip() will block till app in background (y) or (n)
+# This option is reported to be buggy, sometimes failing to restore video state
+NonBlockingSwapBuffers=n
+
+# Redefine common hardware keys to SDL keysyms
+# BACK hardware key is available on all devices, MENU is available on pre-ICS devices, other keys may be absent
+# SEARCH and CALL by default return same keycode as DPAD_CENTER - one of those keys is available on most devices
+# Use word NO_REMAP if you want to preserve native functionality for certain key (volume keys are 3-rd and 4-th)
+# Keys: TOUCHSCREEN (works only when AppUsesMouse=n), DPAD_CENTER/SEARCH, VOLUMEUP, VOLUMEDOWN, MENU, BACK, CAMERA
+RedefinedKeys="SPACE RETURN NO_REMAP NO_REMAP ESCAPE LCTRL F7 F4 F2 MOUSE_LEFT"
+
+# Number of virtual keyboard keys (currently 6 is maximum)
+AppTouchscreenKeyboardKeysAmount=0
+
+# Number of virtual keyboard keys that support autofire (currently 2 is maximum)
+AppTouchscreenKeyboardKeysAmountAutoFire=0
+
+# Redefine on-screen keyboard keys to SDL keysyms - 6 keyboard keys + 4 multitouch gestures (zoom in/out and rotate left/right)
+RedefinedKeysScreenKb="MOUSE_RIGHT F7 LCTRL"
+
+# Names for on-screen keyboard keys, such as Fire, Jump, Run etc, separated by spaces, they are used in SDL config menu
+RedefinedKeysScreenKbNames="MOUSE_RIGHT F7 LCTRL"
+
+# On-screen keys theme
+# 0 = Ultimate Droid by Sean Stieber (green, with gamepad joystick)
+# 1 = Simple Theme by Beholder (white, with gamepad joystick)
+# 2 = Sun by Sirea (yellow, with round joystick)
+# 3 = Keen by Gerstrong (multicolor, with round joystick)
+TouchscreenKeysTheme=1
+
+# Redefine gamepad keys to SDL keysyms, button order is:
+# A B X Y L1 R1 L2 R2 LThumb RThumb
+RedefinedKeysGamepad="MOUSE_RIGHT F7 LCTRL ESCAPE F5 SPACE RETURN MOUSE_LEFT"
+
+# How long to show startup menu button, in msec, 0 to disable startup menu
+StartupMenuButtonTimeout=3000
+
+# Menu items to hide from startup menu, available menu items:
+# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout
+HiddenMenuOptions='SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMouse.DisplaySizeConfig'
+
+# Menu items to show at startup - this is Java code snippet, leave empty for default
+# new SettingsMenuMisc.ShowReadme(), (AppUsesMouse \&\& \! ForceRelativeMouseMode \? new SettingsMenuMouse.DisplaySizeConfig(true) : new SettingsMenu.DummyMenu()), new SettingsMenuMisc.OptionalDownloadConfig(true), new SettingsMenuMisc.GyroscopeCalibration()
+# Available menu items:
+# SettingsMenu.OkButton SettingsMenu.DummyMenu SettingsMenu.MainMenu SettingsMenuMisc.DownloadConfig SettingsMenuMisc.OptionalDownloadConfig SettingsMenuMisc.AudioConfig SettingsMenuMisc.VideoSettingsConfig SettingsMenuMisc.ShowReadme SettingsMenuMisc.GyroscopeCalibration SettingsMenuMisc.ResetToDefaultsConfig SettingsMenuMouse.MouseConfigMainMenu SettingsMenuMouse.DisplaySizeConfig SettingsMenuMouse.LeftClickConfig SettingsMenuMouse.RightClickConfig SettingsMenuMouse.AdditionalMouseConfig SettingsMenuMouse.JoystickMouseConfig SettingsMenuMouse.TouchPressureMeasurementTool SettingsMenuMouse.CalibrateTouchscreenMenu SettingsMenuKeyboard.KeyboardConfigMainMenu SettingsMenuKeyboard.ScreenKeyboardSizeConfig SettingsMenuKeyboard.ScreenKeyboardDrawSizeConfig SettingsMenuKeyboard.ScreenKeyboardThemeConfig SettingsMenuKeyboard.ScreenKeyboardTransparencyConfig SettingsMenuKeyboard.RemapHwKeysConfig SettingsMenuKeyboard.RemapScreenKbConfig SettingsMenuKeyboard.ScreenGesturesConfig SettingsMenuKeyboard.CustomizeScreenKbLayout
+FirstStartMenuOptions=''
+
+# Enable multi-ABI binary, with hardware FPU support - it will also work on old devices,
+# but .apk size is 2x bigger (y) / (n) / (x86) / (all)
+MultiABI="armeabi-v7a"
+
+# Minimum amount of RAM application requires, in Mb, SDL will print warning to user if it's lower
+AppMinimumRAM=256
+
+# Application version code (integer)
+AppVersionCode=@ANDROID_VERSIONCODE@
+
+# Application user-visible version name (string)
+AppVersionName="@VERSION@"
+
+# Reset SDL config when updating application to the new version (y) / (n)
+ResetSdlConfigForThisVersion=y
+
+# Delete application data files when upgrading (specify file/dir paths separated by spaces)
+DeleteFilesOnUpgrade="%"
+
+# Optional shared libraries to compile - removing some of them will save space
+# MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed
+# Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2
+CompiledLibraries="mad vorbis flac ogg jpeg png theora freetype faad"
+
+# Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n)
+CustomBuildScript=y
+
+# Aditional CFLAGS for application
+AppCflags=''
+
+# Additional LDFLAGS for application
+AppLdflags=''
+
+# If application has headers with the same name as system headers, this option tries to fix compiler flags to make it compilable
+AppOverlapsSystemHeaders=
+
+# Build only following subdirs (empty will build all dirs, ignored with custom script)
+AppSubdirsBuild=''
+
+# Exclude these files from build
+AppBuildExclude=''
+
+# Application command line parameters, including app name as 0-th param
+AppCmdline=''
+
+# Here you may type readme text, which will be shown during startup. Format is:
+# Text in English, use \\\\n to separate lines^de:Text in Deutsch^ru:Text in Russian, and so on (that's four backslashes, nice isn't it?)
+ReadmeText='^You may press "Home" now - the data will be downloaded in background'
+
+# Screen size is used by Google Play to prevent an app to be installed on devices with smaller screens
+# Minimum screen size that application supports: (s)mall / (m)edium / (l)arge
+MinimumScreenSize=s
+
+# Your AdMob Publisher ID, (n) if you don't want advertisements
+AdmobPublisherId=n
+
+# Your AdMob test device ID, to receive a test ad
+AdmobTestDeviceId=
+
+# Your AdMob banner size (BANNER/IAB_BANNER/IAB_LEADERBOARD/IAB_MRECT/IAB_WIDE_SKYSCRAPER/SMART_BANNER)
+AdmobBannerSize=
+
+UseGlshim=n
+
+AccessSdCard=y
diff --git a/dists/androidsdl/scummvm/AndroidBuild.sh b/dists/androidsdl/scummvm/AndroidBuild.sh
new file mode 100644
index 0000000000..5cc6863f5e
--- /dev/null
+++ b/dists/androidsdl/scummvm/AndroidBuild.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+LOCAL_PATH=`dirname $0`
+LOCAL_PATH=`cd $LOCAL_PATH && pwd`
+
+#ln -sf libtremor.a $LOCAL_PATH/../../../obj/local/$1/libvorbisidec.a
+ln -sf libflac.a $LOCAL_PATH/../../../obj/local/$1/libFLAC.a
+ln -sf libvorbis.a $LOCAL_PATH/../../../obj/local/$1/libvorbisfile.a
+ln -sf libtheora.so $LOCAL_PATH/../../../obj/local/$1/libtheoradec.so
+ln -sf libglshim.a $LOCAL_PATH/../../../obj/local/$1/libGL.a
+
+if [ \! -f scummvm/config.mk ] ; then
+ ../setEnvironment-$1.sh sh -c "cd scummvm && env LIBS='-lflac -lvorbis -logg -lmad -lz -lgcc -ltheora -lpng -lfreetype -lfaad -lgnustl_static' ./configure --host=androidsdl-$1 --enable-zlib --enable-vorbis --enable-mad --enable-flac --enable-png --enable-theoradec --enable-vkeybd --enable-release --disable-readline --disable-nasm --disable-mt32emu --disable-timidity --disable-fluidsynth --datadir=. "
+fi
+../setEnvironment-$1.sh make -C scummvm -j2 && cp -f scummvm/scummvm libapplication-$1.so
diff --git a/dists/androidsdl/scummvm/AndroidData/logo.png b/dists/androidsdl/scummvm/AndroidData/logo.png
new file mode 100644
index 0000000000..553d97d25e
--- /dev/null
+++ b/dists/androidsdl/scummvm/AndroidData/logo.png
Binary files differ
diff --git a/dists/androidsdl/scummvm/DataBuild.sh b/dists/androidsdl/scummvm/DataBuild.sh
new file mode 100755
index 0000000000..f38c82f8b1
--- /dev/null
+++ b/dists/androidsdl/scummvm/DataBuild.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+LOCAL_PATH=`dirname $0`
+LOCAL_PATH=`cd $LOCAL_PATH && pwd`
+
+rm AndroidData/*
+make -C scummvm androidsdl
+cp -f scummvm/scummvm*.z* AndroidData
+rm scummvm/scummvm*.z* \ No newline at end of file
diff --git a/dists/androidsdl/scummvm/banner.png b/dists/androidsdl/scummvm/banner.png
new file mode 100644
index 0000000000..28a7196b7f
--- /dev/null
+++ b/dists/androidsdl/scummvm/banner.png
Binary files differ
diff --git a/dists/androidsdl/scummvm/icon.png b/dists/androidsdl/scummvm/icon.png
new file mode 100755
index 0000000000..03bc753aab
--- /dev/null
+++ b/dists/androidsdl/scummvm/icon.png
Binary files differ
diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat
index 1b42cfbadc..d49d107f6f 100644
--- a/dists/engine-data/kyra.dat
+++ b/dists/engine-data/kyra.dat
Binary files differ
diff --git a/dists/engine-data/sky.cpt b/dists/engine-data/sky.cpt
index 24c2f03832..cc552105e6 100644
--- a/dists/engine-data/sky.cpt
+++ b/dists/engine-data/sky.cpt
Binary files differ
diff --git a/dists/gcw0/default.gcw0.desktop b/dists/gcw0/default.gcw0.desktop
index 890852184f..9bbb8d5b59 100644
--- a/dists/gcw0/default.gcw0.desktop
+++ b/dists/gcw0/default.gcw0.desktop
@@ -14,3 +14,4 @@ Type=Application
Categories=games;
StartupNotify=false
X-OD-Manual=README.man.txt
+X-OD-NeedsDownscaling=true
diff --git a/dists/gcw0/scummvm.sh b/dists/gcw0/scummvm.sh
index c12a3030cc..7e2bbaf23e 100755
--- a/dists/gcw0/scummvm.sh
+++ b/dists/gcw0/scummvm.sh
@@ -6,4 +6,4 @@ if [ ! -f $HOME/.scummvmrc ] ; then
cp ./scummvmrc $HOME/.scummvmrc
fi
-exec ./scummvm
+exec ./scummvm 2>&1 >/var/tmp/scummvm.log
diff --git a/dists/macosx/DS_Store b/dists/macosx/DS_Store
index 7ad5a19d61..164e7beb9a 100644
--- a/dists/macosx/DS_Store
+++ b/dists/macosx/DS_Store
Binary files differ
diff --git a/dists/macosx/Info.plist b/dists/macosx/Info.plist
index 7f6170294a..ce05e079df 100644
--- a/dists/macosx/Info.plist
+++ b/dists/macosx/Info.plist
@@ -53,7 +53,9 @@
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SUFeedURL</key>
- <string>http://www.scummvm.org/appcasts/macosx/release.xml</string>
+ <string>https://www.scummvm.org/appcasts/macosx/release.xml</string>
+ <key>NSDockTilePlugIn</key>
+ <string>scummvm.docktileplugin</string>
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
</dict>
diff --git a/dists/macosx/Info.plist.in b/dists/macosx/Info.plist.in
index 55be27d77b..c5f54fe3f0 100644
--- a/dists/macosx/Info.plist.in
+++ b/dists/macosx/Info.plist.in
@@ -53,7 +53,9 @@
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SUFeedURL</key>
- <string>http://www.scummvm.org/appcasts/macosx/release.xml</string>
+ <string>https://www.scummvm.org/appcasts/macosx/release.xml</string>
+ <key>NSDockTilePlugIn</key>
+ <string>scummvm.docktileplugin</string>
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
</dict>
diff --git a/dists/macosx/dockplugin/Info.plist b/dists/macosx/dockplugin/Info.plist
new file mode 100644
index 0000000000..c66f96a6b9
--- /dev/null
+++ b/dists/macosx/dockplugin/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>ScummVMDockTilePlugin</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.scummvm.scummvm.DockTilePlugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.9.0git</string>
+ <key>CFBundleVersion</key>
+ <string>1.9.0git</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright 2001-2016 The ScummVM Team</string>
+ <key>NSPrincipalClass</key>
+ <string>ScummVMDockTilePlugIn</string>
+</dict>
+</plist>
diff --git a/dists/macosx/dockplugin/Info.plist.in b/dists/macosx/dockplugin/Info.plist.in
new file mode 100644
index 0000000000..851fc70f11
--- /dev/null
+++ b/dists/macosx/dockplugin/Info.plist.in
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>ScummVMDockTilePlugin</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.scummvm.scummvm.DockTilePlugin</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@VERSION@</string>
+ <key>CFBundleVersion</key>
+ <string>@VERSION@</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright 2001-2016 The ScummVM Team</string>
+ <key>NSPrincipalClass</key>
+ <string>ScummVMDockTilePlugIn</string>
+</dict>
+</plist>
diff --git a/dists/macosx/dsa_pub.pem b/dists/macosx/dsa_pub.pem
new file mode 100644
index 0000000000..13eb86201b
--- /dev/null
+++ b/dists/macosx/dsa_pub.pem
@@ -0,0 +1,36 @@
+-----BEGIN PUBLIC KEY-----
+MIIGOjCCBC0GByqGSM44BAEwggQgAoICAQDMnJLkF6tYuyGHM92pO49c0SV927yl
+g4uteavJXH/AgJlSr/YmouiK5KrWBPoe5gQsxbFjmrt9L8ocwu9OCxNZHlifv7l0
+V4GbBfk11usFjRZXuIS/7N4RPBe0VDuhBoMdViGPBLCUsC/cmOOz4VtiyS1kW0WL
+G2AwWzBT/Zzo4/cDMCys8VBIZjZnjyzxi9u374GdZYNlQ7ts6DbvIxheFBuFG7cg
++XeuB4fz9no1riKM9zEhXtbJJG18/61yvcUj4rOcEYPBFbUXesvuZalVVzYGzZ1G
+p39tuAOK6S7W/AzWeDlAGYAOaMvAukAWTSIj/UeuAPPlnaXQLeZ59+7Fbcc7dvMc
+SIngNszKbmqTPCAOjE1RWUbFoujxEMcoog0iBKNLvgnC9HEL9sfMNma2107xulf6
+ywcHFLC3f8O8RfTBnU4Q8jwI6pY46w5nZ3lmcDpVqF3OGE71z+OPBkVBJpyiRwFJ
+tuCBy4Fc/Vza0QFixoxhREAfxNVza1wrN7DNIFnuhvUM1BwPHx9QvvGAOYJGr+E5
+lrnbpmqYW5icWT/LW+1wlSYTnZeXGTSJFq6Chi6nUyeUov5KdCfJbBu17V727Sj2
+6TKM2HCrE8VmTYSBG99i+2QHhXkV6gOv6reT5lzvzz0BPWRpx9jr48yWU8FxskSE
+5z+GxzBYjqY0+QIVAO2l1PedCvhUPXWR7W4cLPo7na3dAoICACW1k1Omwf60vLnG
+wmxb6hRV44k3UQ/7pwAIGTsepO0caU/5t5lWnmkPnGliXAe7MkJ5Is3aQFdV0kA8
+b0pBsZCpDW3qnJmSJtnO+21n5HMv2b3MFuzvEOCKXNt8RkJxeK/HaLSPQcMH/1GT
+4tCfX7FXZi2VsrV5HxllEVdhMzGC3HBmgXxmO98iVAT9rTfmxqEPwysL/i5DrTXr
+6SCLLYF7BR3bRVjp8y4jmIrGCDS+zqUgbWZR81sd3XcO05TLZr/xxBlY/jZYDbjr
+VG53lIzHTnWp5nugl9CyXrcnzyvDpM/UaiPXxGPXYuK5X4+Kjo937ZegyNWULx6G
++CbcAbFy6R5KtObj9sInnnLjAt2+pIkUxhl8YZnOTraiRBWgnFAxVjTzEYjwlUF8
+gbg8NnAmLQkr/uWtpxdZ2d81pvlrIj0Y3ltzVPx7h5KyXpKItWm08HdPcYiCSXz8
+TIrioSTUcN0ISspsaujmNlAXMeMidrWLXUwL5fMuZ00p7w8gakgUMqbmeEvTkyJO
+iGX5cMqXLp7AXEVFpKzCWg9ebuAWZTkI2v8Kkf466EhIB6OUeeHwWTXpU5Ar8ckU
+MCc+FV9cpe+wQv7AN6SdXamUyJySJ07zcDwXHxpXIq32bANAWO/ZrebcLi5AUOs0
+rmiOk+ET2LzzfJjnmBnb0lELrvzbA4ICBQACggIAXh4VEPZbBDyfCvGDTGIjxxs9
+0uApTVBVyAzHTQ+J9OKsaoqbMF8QADczTXaE0ycaZZDcq1jHeAkL/UwAfm1gRyhn
+jIWX+quZHv1hI2r114gxkvwa8FNvQKffkeYZ9r7NsCyuhBlSHbFuNgYbByTZ16v6
+s0KfMPgTVMb5LANDD6SwUhb8ggvbEnWrO8l6Cn8tKaCwSVfYF37cECCoqc+yLW+S
+0rvJxr/aULAGuEBTA3uwuFOMhWveRNbRqOOfqvOkdGFyUL1zjmNEHNx7qJNU2sni
+BbU2DQd01s6uPyWQOXXm77VG1TQo4Z2+OVZSvS8oyNRJaXmqfKf72rW14GERSb40
+qEL6RlltWjPw5Kezv/OdOrE6vKO2uprvpSkOARm9W2jJbJm9hpXvyHUljxJOkYR2
+VxCMVO74DbhDKFuh115wMy2g/FoDy/QbbvgsKOWgBNkgp+xbclo4bJdmvzihwScy
+hCeCKKzQDZtu9JSaUnOMvx3hjL7hMAzjRP92Cmly0YoRNuLqzX4OqPTr/Si5au0C
+/IiySlBxPUkoP1HQVXm9vU4pI4D/ViDJpXx2UKN9/nFQW1exC/n1TeGavnuT4HY1
+vAt/3wPz3asTCBIULmqGOEsgOo3nN3pfnBmmGDjUWg8i79RNCbLgLkcMtJ0F1xvq
+pYCWvL3Wewrmz0Yc790=
+-----END PUBLIC KEY-----
diff --git a/dists/macosx/scummvm_appcast.xml b/dists/macosx/scummvm_appcast.xml
new file mode 100644
index 0000000000..35fbc54908
--- /dev/null
+++ b/dists/macosx/scummvm_appcast.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <channel>
+ <title>ScummVM Changelog</title>
+ <link>https://www.scummvm.org/appcasts/macosx/release.xml</link>
+ <description>Most recent changes with links to updates.</description>
+ <language>en</language>
+ <item>
+ <title>Version 1.8.1</title>
+ <sparkle:releaseNotesLink>
+ https://scummvm.org/frs/scummvm/1.8.1/ReleaseNotes
+ </sparkle:releaseNotesLink>
+ <pubDate>Wed, 25 May 2016 19:26:00 +0000</pubDate>
+ <enclosure url="https://www.scummvm.org/frs/scummvm/1.8.1/scummvm-1.8.1-macosx.dmg"
+ sparkle:version="1.8.1" length="15791070" type="application/octet-stream"
+ sparkle:dsaSignature="MC0CFQDF0u/pGH51pMPzCbsv07eCNxuGDQIUdrKWVTznbF69fzuzIieR4Lc0U2Y=" />
+ </item>
+ <item>
+ <title>Version 1.8.0</title>
+ <sparkle:releaseNotesLink>
+ https://scummvm.org/frs/scummvm/1.8.0/ReleaseNotes
+ </sparkle:releaseNotesLink>
+ <pubDate>Sat, 5 Mar 2016 20:16:00 +0000</pubDate>
+ <enclosure url="https://www.scummvm.org/frs/scummvm/1.8.0/scummvm-1.8.0-macosx.dmg"
+ sparkle:version="1.8.0" length="14085288" type="application/octet-stream"
+ sparkle:dsaSignature="MC0CFQDNy2yox7vklthHaZcMto8L4EuLwQIUY8cuevlTpLtuJ9nPOlrj4vo55lY=" />
+ <enclosure sparkle:os="windows"
+ url="https://www.scummvm.org/frs/scummvm/1.8.0/scummvm-1.8.0-win32.exe"
+ sparkle:version="1.8.0" length="9081062" type="application/octet-stream"
+ sparkle:dsaSignature="MC0CFQCaG7Oo+Nc2EWVmc7GjUBJLKRvt3QIUQcZTMe2FQhfvrrofX4HLTldDHyY=" />
+ </item>
+ <item>
+ <title>Version 1.7.0</title>
+ <sparkle:releaseNotesLink>
+ https://www.scummvm.org/frs/scummvm/1.7.0/ReleaseNotes
+ </sparkle:releaseNotesLink>
+ <sparkle:version>1.7.0</sparkle:version>
+ <pubDate>Tue, 29 Jul 2014 07:58:00 +0000</pubDate>
+ <link>https://www.scummvm.org/frs/scummvm/1.7.0/</link>
+ </item>
+ </channel>
+</rss>
diff --git a/dists/macosx/scummvm_osx_appcast.xml b/dists/macosx/scummvm_osx_appcast.xml
deleted file mode 100644
index 455b062b6b..0000000000
--- a/dists/macosx/scummvm_osx_appcast.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
- <channel>
- <title>ScummVM Changelog</title>
- <link>http://scummvm.org/scummvm_appcast.xml</link>
- <description>Most recent changes with links to updates.</description>
- <language>en</language>
- <item>
- <title>Version 1.2.1 (3 bugs fixed; 2 new features)</title>
- <sparkle:releaseNotesLink>
- http://sourceforge.net/projects/scummvm/files/scummvm/1.2.1/ReleaseNotes/view
- </sparkle:releaseNotesLink>
- <pubDate>Sun, 19 Dec 2010 12:20:11 +0000</pubDate>
- <enclosure url="http://scummvm.org/ScummVM 1.2.1-Test.zip" sparkle:version="1.2.1" length="1472893" type="application/octet-stream" sparkle:dsaSignature="234818feCa1JyW30nbkBwainOzrN6EQuAh" />
- </item>
- <item>
- <title>Version 1.2.0</title>
- <sparkle:releaseNotesLink>
- http://sourceforge.net/projects/scummvm/files/scummvm/1.2.0/ReleaseNotes/view
- </sparkle:releaseNotesLink>
- <pubDate>Fri, 15 Oct 2010 12:20:11 +0000</pubDate>
- <enclosure url="http://scummvm.org/ScummVM 1.2.0-Test.zip" sparkle:version="1.2.0" length="1472893" type="application/octet-stream" sparkle:dsaSignature="234818feCa1JyW30nbkBwainOzrN6EQuAh" />
- </item>
- </channel>
-</rss>
diff --git a/dists/openpandora/pnd_make.sh b/dists/openpandora/pnd_make.sh
index 202f137acc..a24beaf5d4 100755
--- a/dists/openpandora/pnd_make.sh
+++ b/dists/openpandora/pnd_make.sh
@@ -42,14 +42,14 @@ cecho () # Color-echo. Argument $1 = message, Argument $2 = color
local default_msg="No message passed." # Doesn't really need to be a local variable.
message=${1:-$default_msg} # Defaults to default message.
- # We only output colors when a TERM environment variable is set. This
- # fixes execution of the script on buildbot, which does not have this set.
- if [ -z "$TERM" ]; then
- echo "$message"
- else
+ # We only output colors when stdout is outputting to a terminal.
+ # This avoids color codes being output in log files created on buildbot.
+ if [ -t 1 -a -n "$TERM" ]; then
color=${2:-$black} # Defaults to black, if not specified.
echo -e "$color$message"
- tput sgr0 # Reset to normal.
+ tput -T"$TERM" sgr0 # Reset to normal.
+ else
+ echo "$message"
fi
return
}
diff --git a/dists/scummvm.rc b/dists/scummvm.rc
index aad521fddd..873feaa419 100644
--- a/dists/scummvm.rc
+++ b/dists/scummvm.rc
@@ -81,6 +81,7 @@ BEGIN
BLOCK "040904b0" // US English, Unicode
BEGIN
VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0"
+ VALUE "CompanyName", "scummvm.org\0"
VALUE "FileDescription", "http://www.scummvm.org/\0"
VALUE "FileVersion", "1.9.0git\0"
VALUE "InternalName", "scummvm\0"
diff --git a/dists/scummvm.rc.in b/dists/scummvm.rc.in
index 34a4948381..2e0a5ff745 100644
--- a/dists/scummvm.rc.in
+++ b/dists/scummvm.rc.in
@@ -81,6 +81,7 @@ BEGIN
BLOCK "040904b0" // US English, Unicode
BEGIN
VALUE "Comments", "Look! A three headed monkey (TM)! .. Nice use of the TM!\0"
+ VALUE "CompanyName", "scummvm.org\0"
VALUE "FileDescription", "http://www.scummvm.org/\0"
VALUE "FileVersion", "@VERSION@\0"
VALUE "InternalName", "scummvm\0"
diff --git a/doc/cz/PrectiMe b/doc/cz/PrectiMe
index 3c03db9802..030ddac916 100644
--- a/doc/cz/PrectiMe
+++ b/doc/cz/PrectiMe
@@ -651,7 +651,7 @@ Abyste mohli spustit verzi pro Mac OS X od Wyrmkeep musíte data zkopírovat z 
<http://wiki.scummvm.org/index.php/HOWTO-Mac_Games>
-I když se v tomto Älánku píše hlavnÄ› o hrách SCUMM, je zde také zmínÄ›n nástroj "HFVExplorer", který potÅ™ebujete k extrakci souborů. Nezapomeňte, že data Å™eÄi "Inherit the Earth Voices" musíte umístit do stejného adresáře, kde jsou uložena data hry:
+I když se v tomto Älánku píše hlavnÄ› o hrách SCUMM, je zde také zmínÄ›n nástroj "HFSExplorer", který potÅ™ebujete k extrakci souborů. Nezapomeňte, že data Å™eÄi "Inherit the Earth Voices" musíte umístit do stejného adresáře, kde jsou uložena data hry:
Inherit the Earth.app/Contents/Resources
@@ -915,7 +915,7 @@ Nebo můžete použít 'extract_mm_c64' z balíÄku nástrojů pro extrahovánÃ
3.26) Poznámky ke hrám Macintosh:
----- ---------------------------
-VÅ¡echny adventury LucasArts založené na SCUMM, kromÄ› COMI, také existují ve verzích pro in Macintosh. ScummVM může vÄ›tÅ¡inu (vÅ¡echny?) použít, nicménÄ›, v nÄ›kterých případech je nutná dodateÄná práce. Nejdříve, pokud pro toto nepoužíváte Macintosh, přístup k datům na CD/disketÄ› může být obtížný. Důvodem je to, že Mac používá zvláštní formát disku nazvaný HFS, který ostatní systémy vÄ›tÅ¡inou nepodporují. NicménÄ› existuje, nÄ›kolik nástrojů, které jsou zadarmo a umožňují Äíst takovéto svazky HFS. Například "HFVExplorer" pro Windows a "hfsutils" pro Linux a ostatní Unixové operaÄní systémy.
+VÅ¡echny adventury LucasArts založené na SCUMM, kromÄ› COMI, také existují ve verzích pro in Macintosh. ScummVM může vÄ›tÅ¡inu (vÅ¡echny?) použít, nicménÄ›, v nÄ›kterých případech je nutná dodateÄná práce. Nejdříve, pokud pro toto nepoužíváte Macintosh, přístup k datům na CD/disketÄ› může být obtížný. Důvodem je to, že Mac používá zvláštní formát disku nazvaný HFS, který ostatní systémy vÄ›tÅ¡inou nepodporují. NicménÄ› existuje, nÄ›kolik nástrojů, které jsou zadarmo a umožňují Äíst takovéto svazky HFS. Například "HFSExplorer" pro Windows a "hfsutils" pro Linux a ostatní Unixové operaÄní systémy.
VÄ›tÅ¡ina novÄ›jších her na Macintosh je dodávána pouze s jedním datovým souborem (v nÄ›kterých případech byl tento soubor uÄinÄ›n neviditelným, takže možná budete potÅ™ebovat dodateÄné nástroje, abyste ho mohli zkopírovat). ScummVM je schopen takovýto soubor použít přímo; jednoduÅ¡e odkažte ScummVM na složku obsahující tento soubor a mÄ›lo by to fungovat (tak jako s každou podporovanou hrou).
diff --git a/doc/de/Liesmich b/doc/de/Liesmich
index f37fc7d396..84eb6b53fd 100644
--- a/doc/de/Liesmich
+++ b/doc/de/Liesmich
@@ -878,7 +878,7 @@ einem PC arbeiten, lesen Sie hierfür:
http://wiki.scummvm.org/index.php/HOWTO-Mac_Games
Obwohl hier in erster Linie über SCUMM-Spiele gesprochen wird, findet das
-Dienstprogramm „HFVExplorer“ Erwähnung, welches Sie benötigen, um die Dateien zu
+Dienstprogramm „HFSExplorer“ Erwähnung, welches Sie benötigen, um die Dateien zu
extrahieren. Beachten Sie, dass Sie die Sprachausgabedaten aus „Inherit the
Earth Voices“ im selben Verzeichnis ablegen müssen wie die Spieldaten, die sich
an folgendem Ort befinden:
@@ -1280,7 +1280,7 @@ kompliziert werden, auf die CD- oder Diskettendaten zuzugreifen. Der Grund
hierfür ist, dass der Mac ein spezielles Datenträgerformat nutzt, welches sich
HFS nennt, und das andere Systeme normalerweise nicht unterstützen. Es gibt
jedoch zahlreiche kostenlose Tools, die es ermöglichen, einen solchen
-HFS-Datenträger zu lesen. Z. B. „HFVExplorer“ für Windows und „hfsutils“ für
+HFS-Datenträger zu lesen. Z. B. „HFSExplorer“ für Windows und „hfsutils“ für
Linux und andere Betriebssysteme, die Unix ähnlich sind.
Die meisten neueren Spiele für den Macintosh wurden nur mit einer einzigen
diff --git a/doc/de/Neues b/doc/de/Neues
index 3643aa8cba..6870accf40 100644
--- a/doc/de/Neues
+++ b/doc/de/Neues
@@ -2,6 +2,115 @@ Umfangreichere Informationen über die Änderungen des aktuellen experimentellen
Programmcodes finden Sie auf Englisch unter:
https://github.com/scummvm/scummvm/commits/
+1.9.0 (DD.MM.YYYY)
+ Neue Spiele:
+ - Unterstützung für Myst hinzugefügt.
+ - Unterstützung für Myst: Masterpiece Edition hinzugefügt.
+ - Unterstützung für U.F.O.s./Gnap: Der Schurke aus dem All hinzugefügt.
+
+ AGI:
+ - Unterstützung für Hercules-Darstellung (Grün + Bernstein) hinzugefügt.
+ - Unterstützung für hochauflösende Hercules-Schriftart hinzugefügt
+ (auch außerhalb der Hercules-Darstellung nutzbar).
+ - Optionale Funktion "Pause, wenn Befehle eingegeben werden" hinzugefügt.
+ Diese Funktion war im originalen Interpreter nur im Hercules-Darstellungsmodus
+ verfügbar.
+
+ SCI:
+ - Fehlende Dialogzeile in QfG3 hinzugefügt, die mit drei zusätzlichen Punkten
+ belohnt wird. Diese Dialogzeile fehlt im Originalspiel, weshalb
+ es bislang unmöglich war, die maximale Punktzahl im Spiel zu erreichen.
+
+ Windows-Portierung:
+ - Taskleisten-Integration unter Windows 10 und höher repariert.
+
+1.8.1 (25.05.2016)
+ Neue Portierungen:
+ - Portierung für den Nintendo 3DS hinzugefügt.
+ - Portierung für Android SDL hinzugefügt.
+
+ Allgemein:
+ - "TESTING"-Markierung von mehreren unterstützten Spielen entfernt.
+ - Chinesische Übersetzung (Pinyin) der Benutzeroberfläche hinzugefügt.
+ - Ruckeln des Mauszeigers im ScummVM-Programmfenster behoben, welches auf
+ einigen Systemen auftrat.
+
+ BBVS:
+ - Fehler beim erneuten Starten des Spiels behoben.
+
+ CinE:
+ - Fehler beim Laden der Soundeffekte behoben.
+
+ Drascula:
+ - Text-Ausrichtung ist jetzt originalgetreu.
+ - Charakter tritt nicht mehr aus dem Bildschirmbereich heraus.
+ - Laden eines Spielstandes in der "Pendulum"-Szene repariert.
+ - Falscher Hintergrund für Inventar-Gegenstände im Kapitel 6 in der
+ spanischen Version korrigiert.
+ - Geschwindigkeit der Animationen korrigiert. Animationen wurden nur halb
+ so schnell wie im originalen Interpreter abgespielt.
+ - Rauschen am Beginn und/oder am Ende der Sprachausgabe behoben.
+ Dieser Fehler trat hauptsächlich in der spanischen Version auf.
+ - Verzögerung während der Interaktion mit dem Verben-Menü und dem Inventar behoben.
+ - Fehler behoben, durch den die Axt im Schloss mehrfach aufgehoben werden konnte.
+
+ Gob:
+ - Aufhängen während Sound-Initialisierung in mehreren Spielen behoben.
+
+ KYRA:
+ - Potentieller Absturz behoben, der in "Hand of Fate" auftritt, wenn der
+ Sumpfschlangentrank an der Ratte verwendet wird.
+ (HINWEIS: Dieser Fehler wurde bereits in Version 1.8.0 behoben,
+ jedoch nicht in der Neues-Datei erwähnt).
+ - Fehlende Stimm-Reaktionen korrigiert, wenn Gegner in der CD-Version von
+ Lands of Lore getroffen wurden.
+
+ Lab:
+ - Aufhängen während der End-Sequenz behoben.
+ - Interne Spiel-Bedienelemente verbessert.
+ - Aufhängen bei einigen Animationen im Spiel behoben.
+
+ SAGA:
+ - Fehlerhafte Farben der Bedienelemente in der französischen und deutschen
+ Version von "I Have No Mouth and I Must Scream" korrigiert.
+
+ SCI:
+ - Cursor-Hilfsroutinen funktionieren nun korrekt auf OpenPandora und anderen
+ Geräten, die einen Touchscreen und analoge Sticks/Mäuse zur gleichen Zeit
+ unterstützen.
+ - Skript-Fehlerbehebung, um den fehlerhaften Endkampf in der mehrsprachigen
+ Version von King's Quest 5 zu korrigieren. Betroffen sind die französische,
+ deutsche und spanische Version.
+ - Ungültiger Speicherzugriff beim Laden der defekten Audiospur im Abspann
+ von King's Quest 5 behoben.
+ - Probleme mit der Einstellung der Bildschirmauflösung beim Speichern in
+ King's Quest 6 behoben.
+
+ SCUMM:
+ - Erkennung von Maniac Mansion innerhalb von Day of the Tentacle in der
+ Windows-Version von ScummVM repariert.
+ - In der EGA-Version von Loom wurde ein Sound-Effekt nicht korrekt angehalten,
+ wenn AdLib verwendet wurde. Dieser Fehler wurde behoben.
+
+ Baphomets Fluch 2.5:
+ - Option zur Auswahl von englischer Sprachausgabe anstelle der deutschen,
+ wenn in der gewählten Sprache keine Sprachausgabe verfügbar ist, hinzugefügt.
+ - Ressourcen-Freigabe beim Beenden des Spiels korrigiert.
+ - Fehler beim Neustart des Spiels nach dem Wechsel der Spiel-Sprache behoben.
+ - Flackern im Hauptmenü behoben.
+ - Lange Dauer des Speichervorgangs unter Windows behoben.
+
+ Windows-Portierung:
+ - Absturz im Zusammenhang mit nicht-funktionierenden MIDI-Geräten behoben.
+
+ Mac OS X-Portierung:
+ - Das Dock-Menü für ScummVM enthält nun eine Liste der zuletzt gespielten Spiele,
+ wenn ScummVM nicht läuft, und ermöglicht den direkten Start dieser Spiele.
+ - Sparkle-Updater für vereinfachte Programmaktualisierungen hinzugefügt.
+
+ GCW0-Portierung:
+ - Verbesserte Unterstützung für die in ScummVM integrierte Dokumentation.
+
1.8.0 (04.03.2016)
Neue Spiele:
- Unterstützung für Rex Nebular and the Cosmic Gender Bender hinzugefügt.
@@ -18,7 +127,7 @@ Programmcodes finden Sie auf Englisch unter:
hinzugefügt.
- Unterstützung für Labyrinth of Time hinzugefügt.
-Neue Portierungen:
+ Neue Portierungen:
- Portierung für den Raspberry Pi hinzugefügt.
- Portierung für den GCW Zero (GCW0) hinzugefügt.
@@ -28,7 +137,7 @@ Neue Portierungen:
SDL:
- Alt+x beendet ScummVM nicht mehr. Verwenden Sie stattdessen
Cmd+q/Strg+q/Strg+z und beachten Sie die Hinweise in der Liesmich-Datei.
- - Auf POSIX-Systemen befolgen wir nun die Spezifikation XDG Base Directory
+ - Auf POSIX-Systemen befolgen wir nun die Spezifikation XDG Base Directory
für die Speicherung von Benutzerdaten. Dies führt zu neuen
Speicherorten für unsere Konfigurationsdatei, unsere Log-Datei sowie für
den standardmäßig voreingestellten Speicherort für Spielstände. Wir
@@ -56,7 +165,7 @@ Neue Portierungen:
(verwendet von Mixed Up Mother Goose).
- Feste Verzögerung von 2 Sekunden bei Raumwechseln entfernt und durch
Heuristik ersetzt.
- - Fehlerhafte Tastenbelegungen nach abspeichern/laden behoben
+ - Fehlerhafte Tastenbelegungen nach abspeichern/laden behoben.
AGOS:
- Arpeggio-Effekt in der Musik der Amiga-Version von Elvira 1 repariert.
@@ -68,7 +177,7 @@ Neue Portierungen:
AdLib-Ausgabe erheblich und erhöht die Originaltreue.
Baphomets Fluch 1:
- - Sprachausgabe in Macintosh-Versionen korrigiert, wenn ScumMVM
+ - Sprachausgabe in Macintosh-Versionen korrigiert, wenn ScummVM
auf Big-Endian-Systemen ausgeführt wird.
- Fehler beim Laden eines Spielstandes aus dem Hauptmenü in der
Bull's Head Hill-Szene korrigiert. Dieser Fehler trat womöglich auch
diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index bc9bcb4b08..6f91bd76dd 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -244,7 +244,7 @@ void AccessEngine::freeCells() {
}
}
-void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
+void AccessEngine::speakText(BaseSurface *s, const Common::String &msg) {
Common::String lines = msg;
Common::String line;
int curPage = 0;
@@ -325,7 +325,7 @@ void AccessEngine::speakText(ASurface *s, const Common::String &msg) {
}
}
-void AccessEngine::printText(ASurface *s, const Common::String &msg) {
+void AccessEngine::printText(BaseSurface *s, const Common::String &msg) {
Common::String lines = msg;
Common::String line;
int width = 0;
@@ -436,20 +436,9 @@ void AccessEngine::copyBF1BF2() {
}
void AccessEngine::copyBF2Vid() {
- const byte *srcP = (const byte *)_buffer2.getPixels();
- byte *destP = (byte *)_screen->getBasePtr(_screen->_windowXAdd,
- _screen->_windowYAdd + _screen->_screenYOff);
-
- for (int yp = 0; yp < _screen->_vWindowLinesTall; ++yp) {
- Common::copy(srcP, srcP + _screen->_vWindowBytesWide, destP);
- srcP += _buffer2.pitch;
- destP += _screen->pitch;
- }
-
- // Add dirty rect for affected area
- Common::Rect r(_screen->_vWindowBytesWide, _screen->_vWindowLinesTall);
- r.moveTo(_screen->_windowXAdd, _screen->_windowYAdd + _screen->_screenYOff);
- _screen->addDirtyRect(r);
+ _screen->blitFrom(_buffer2,
+ Common::Rect(0, 0, _screen->_vWindowBytesWide, _screen->_vWindowLinesTall),
+ Common::Point(_screen->_windowXAdd, _screen->_windowYAdd));
}
void AccessEngine::playVideo(int videoNum, const Common::Point &pt) {
diff --git a/engines/access/access.h b/engines/access/access.h
index 2ca4a3468e..972dd4c380 100644
--- a/engines/access/access.h
+++ b/engines/access/access.h
@@ -156,8 +156,8 @@ public:
MusicManager *_midi;
VideoPlayer *_video;
- ASurface *_destIn;
- ASurface *_current;
+ BaseSurface *_destIn;
+ BaseSurface *_current;
ASurface _buffer1;
ASurface _buffer2;
ASurface _vidBuf;
@@ -280,8 +280,8 @@ public:
/**
* Draw a string on a given surface and update text positioning
*/
- void printText(ASurface *s, const Common::String &msg);
- void speakText(ASurface *s, const Common::String &msg);
+ void printText(BaseSurface *s, const Common::String &msg);
+ void speakText(BaseSurface *s, const Common::String &msg);
/**
* Load a savegame
diff --git a/engines/access/amazon/amazon_game.cpp b/engines/access/amazon/amazon_game.cpp
index 0a671d23d2..8467d8b623 100644
--- a/engines/access/amazon/amazon_game.cpp
+++ b/engines/access/amazon/amazon_game.cpp
@@ -496,7 +496,7 @@ void AmazonEngine::drawHelp(const Common::String str) {
_files->loadScreen(95, 2);
if (_moreHelp == 1) {
- ASurface *oldDest = _destIn;
+ BaseSurface *oldDest = _destIn;
_destIn = _screen;
int oldClip = _screen->_clipHeight;
_screen->_clipHeight = 200;
diff --git a/engines/access/amazon/amazon_logic.cpp b/engines/access/amazon/amazon_logic.cpp
index e78f92cda7..08006fe1b7 100644
--- a/engines/access/amazon/amazon_logic.cpp
+++ b/engines/access/amazon/amazon_logic.cpp
@@ -185,16 +185,24 @@ void CampScene::mWhileDoOpen() {
_vm->_numAnimTimers = 0;
_vm->_images.clear();
- if (_vm->_conversation == 2) {
- // Cutscene at end of Chapter 6
- Resource *spriteData = _vm->_files->loadFile(28, 37);
- _vm->_objectsTable[28] = new SpriteResource(_vm, spriteData);
- delete spriteData;
-
- _vm->_animation->freeAnimationData();
- animResource = _vm->_files->loadFile(28, 38);
- _vm->_animation->loadAnimations(animResource);
- delete animResource;
+ if (_vm->isCD()) {
+ if (_vm->_conversation == 2) {
+ // Cutscene at end of Chapter 6
+ Resource *spriteData = _vm->_files->loadFile(28, 37);
+ _vm->_objectsTable[28] = new SpriteResource(_vm, spriteData);
+ delete spriteData;
+
+ _vm->_animation->freeAnimationData();
+ animResource = _vm->_files->loadFile(28, 38);
+ _vm->_animation->loadAnimations(animResource);
+ delete animResource;
+ }
+ } else {
+ _vm->freeCells();
+ _vm->_oldRects.clear();
+ _vm->_newRects.clear();
+ _vm->_numAnimTimers = 0;
+ _vm->_images.clear();
}
}
diff --git a/engines/access/asurface.cpp b/engines/access/asurface.cpp
index f693e6a3a0..37f4c7082e 100644
--- a/engines/access/asurface.cpp
+++ b/engines/access/asurface.cpp
@@ -107,10 +107,11 @@ void ImageEntryList::addToList(ImageEntry &ie) {
/*------------------------------------------------------------------------*/
-int ASurface::_clipWidth;
-int ASurface::_clipHeight;
+int BaseSurface::_clipWidth;
+int BaseSurface::_clipHeight;
-ASurface::ASurface(): Graphics::Surface() {
+BaseSurface::BaseSurface(): Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_leftSkip = _rightSkip = 0;
_topSkip = _bottomSkip = 0;
_lastBoundsX = _lastBoundsY = 0;
@@ -121,67 +122,16 @@ ASurface::ASurface(): Graphics::Surface() {
_maxChars = 0;
}
-ASurface::~ASurface() {
- free();
+BaseSurface::~BaseSurface() {
_savedBlock.free();
}
-void ASurface::create(uint16 width, uint16 height) {
- Graphics::Surface::create(width, height, Graphics::PixelFormat::createFormatCLUT8());
-}
-
-void ASurface::clearBuffer() {
+void BaseSurface::clearBuffer() {
byte *pSrc = (byte *)getPixels();
Common::fill(pSrc, pSrc + w * h, 0);
}
-bool ASurface::clip(Common::Rect &r) {
- int skip;
- _leftSkip = _rightSkip = 0;
- _topSkip = _bottomSkip = 0;
-
- if (r.left > _clipWidth || r.left < 0) {
- if (r.left >= 0)
- return true;
-
- skip = -r.left;
- r.setWidth(r.width() - skip);
- _leftSkip = skip;
- r.moveTo(0, r.top);
- }
-
- int right = r.right - 1;
- if (right < 0)
- return true;
- else if (right > _clipWidth) {
- skip = right - _clipWidth;
- r.setWidth(r.width() - skip);
- _rightSkip = skip;
- }
-
- if (r.top > _clipHeight || r.top < 0) {
- if (r.top >= 0)
- return true;
-
- skip = -r.top;
- r.setHeight(r.height() - skip);
- _topSkip = skip;
- r.moveTo(r.left, 0);
- }
-
- int bottom = r.bottom - 1;
- if (bottom < 0)
- return true;
- else if (bottom > _clipHeight) {
- skip = bottom - _clipHeight;
- _bottomSkip = skip;
- r.setHeight(r.height() - skip);
- }
-
- return false;
-}
-
-void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) {
+void BaseSurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt) {
SpriteFrame *frame = sprite->getFrame(frameNum);
Common::Rect r(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h);
@@ -195,115 +145,38 @@ void ASurface::plotImage(SpriteResource *sprite, int frameNum, const Common::Poi
}
}
-void ASurface::transBlitFrom(ASurface *src, const Common::Point &destPos) {
- if (getPixels() == nullptr)
- create(w, h);
-
- for (int yp = 0; yp < src->h; ++yp) {
- const byte *srcP = (const byte *)src->getBasePtr(0, yp);
- byte *destP = (byte *)getBasePtr(destPos.x, destPos.y + yp);
-
- for (int xp = 0; xp < this->w; ++xp, ++srcP, ++destP) {
- if (*srcP != TRANSPARENCY)
- *destP = *srcP;
- }
- }
-}
-
-void ASurface::transBlitFrom(ASurface *src, const Common::Rect &bounds) {
- const int SCALE_LIMIT = 0x100;
- int scaleX = SCALE_LIMIT * bounds.width() / src->w;
- int scaleY = SCALE_LIMIT * bounds.height() / src->h;
- int scaleXCtr = 0, scaleYCtr = 0;
-
- for (int yCtr = 0, destY = bounds.top; yCtr < src->h; ++yCtr) {
- // Handle skipping lines if Y scaling
- scaleYCtr += scaleY;
- if (scaleYCtr < SCALE_LIMIT)
- continue;
- scaleYCtr -= SCALE_LIMIT;
-
- // Handle off-screen lines
- if (destY >= this->h)
- break;
-
- if (destY >= 0) {
- // Handle drawing the line
- const byte *pSrc = (const byte *)src->getBasePtr(0, yCtr);
- byte *pDest = (byte *)getBasePtr(bounds.left, destY);
- scaleXCtr = 0;
- int x = bounds.left;
-
- for (int xCtr = 0; xCtr < src->w; ++xCtr, ++pSrc) {
- // Handle horizontal scaling
- scaleXCtr += scaleX;
- if (scaleXCtr < SCALE_LIMIT)
- continue;
- scaleXCtr -= SCALE_LIMIT;
-
- // Only handle on-screen pixels
- if (x >= this->w)
- break;
- if (x >= 0 && *pSrc != 0)
- *pDest = *pSrc;
-
- ++pDest;
- ++x;
- }
- }
-
- ++destY;
- }
-}
-
-void ASurface::transBlitFrom(ASurface &src) {
- blitFrom(src);
-}
-
-void ASurface::blitFrom(const Graphics::Surface &src) {
- assert(w >= src.w && h >= src.h);
- for (int y = 0; y < src.h; ++y) {
- const byte *srcP = (const byte *)src.getBasePtr(0, y);
- byte *destP = (byte *)getBasePtr(0, y);
- Common::copy(srcP, srcP + src.w, destP);
- }
-}
-
-void ASurface::copyBuffer(Graphics::Surface *src) {
+void BaseSurface::copyBuffer(Graphics::ManagedSurface *src) {
blitFrom(*src);
}
-void ASurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
+void BaseSurface::plotF(SpriteFrame *frame, const Common::Point &pt) {
sPlotF(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
}
-void ASurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
+void BaseSurface::plotB(SpriteFrame *frame, const Common::Point &pt) {
sPlotB(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
}
-void ASurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
- transBlitFrom(frame, bounds);
+void BaseSurface::sPlotF(SpriteFrame *frame, const Common::Rect &bounds) {
+ transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, false);
}
-void ASurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
- ASurface flippedFrame;
- frame->flipHorizontal(flippedFrame);
-
- transBlitFrom(&flippedFrame, bounds);
+void BaseSurface::sPlotB(SpriteFrame *frame, const Common::Rect &bounds) {
+ transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, true);
}
-void ASurface::copyBlock(ASurface *src, const Common::Rect &bounds) {
+void BaseSurface::copyBlock(BaseSurface *src, const Common::Rect &bounds) {
copyRectToSurface(*src, bounds.left, bounds.top, bounds);
}
-void ASurface::copyTo(ASurface *dest) {
+void BaseSurface::copyTo(BaseSurface *dest) {
if (dest->empty())
dest->create(this->w, this->h);
dest->blitFrom(*this);
}
-void ASurface::saveBlock(const Common::Rect &bounds) {
+void BaseSurface::saveBlock(const Common::Rect &bounds) {
_savedBounds = bounds;
_savedBounds.clip(Common::Rect(0, 0, this->w, this->h));
@@ -313,7 +186,7 @@ void ASurface::saveBlock(const Common::Rect &bounds) {
_savedBlock.copyRectToSurface(*this, 0, 0, _savedBounds);
}
-void ASurface::restoreBlock() {
+void BaseSurface::restoreBlock() {
if (!_savedBounds.isEmpty()) {
copyRectToSurface(_savedBlock, _savedBounds.left, _savedBounds.top,
Common::Rect(0, 0, _savedBlock.w, _savedBlock.h));
@@ -323,26 +196,26 @@ void ASurface::restoreBlock() {
}
}
-void ASurface::drawRect() {
- Graphics::Surface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor);
+void BaseSurface::drawRect() {
+ Graphics::ManagedSurface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor);
}
-void ASurface::drawLine(int x1, int y1, int x2, int y2, int col) {
- Graphics::Surface::drawLine(x1, y1, x2, y2, col);
+void BaseSurface::drawLine(int x1, int y1, int x2, int y2, int col) {
+ Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, col);
}
-void ASurface::drawLine() {
- Graphics::Surface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
+void BaseSurface::drawLine() {
+ Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
}
-void ASurface::drawBox() {
- Graphics::Surface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
- Graphics::Surface::drawLine(_orgX1, _orgY2, _orgX2, _orgY2, _lColor);
- Graphics::Surface::drawLine(_orgX2, _orgY1, _orgX2, _orgY1, _lColor);
- Graphics::Surface::drawLine(_orgX2, _orgY2, _orgX2, _orgY2, _lColor);
+void BaseSurface::drawBox() {
+ Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
+ Graphics::ManagedSurface::drawLine(_orgX1, _orgY2, _orgX2, _orgY2, _lColor);
+ Graphics::ManagedSurface::drawLine(_orgX2, _orgY1, _orgX2, _orgY1, _lColor);
+ Graphics::ManagedSurface::drawLine(_orgX2, _orgY2, _orgX2, _orgY2, _lColor);
}
-void ASurface::flipHorizontal(ASurface &dest) {
+void BaseSurface::flipHorizontal(BaseSurface &dest) {
dest.create(this->w, this->h);
for (int y = 0; y < h; ++y) {
const byte *pSrc = (const byte *)getBasePtr(this->w - 1, y);
@@ -353,24 +226,70 @@ void ASurface::flipHorizontal(ASurface &dest) {
}
}
-void ASurface::moveBufferLeft() {
+void BaseSurface::moveBufferLeft() {
byte *p = (byte *)getPixels();
Common::copy(p + TILE_WIDTH, p + (w * h), p);
}
-void ASurface::moveBufferRight() {
+void BaseSurface::moveBufferRight() {
byte *p = (byte *)getPixels();
Common::copy_backward(p, p + (pitch * h) - TILE_WIDTH, p + (pitch * h));
}
-void ASurface::moveBufferUp() {
+void BaseSurface::moveBufferUp() {
byte *p = (byte *)getPixels();
Common::copy(p + (pitch * TILE_HEIGHT), p + (pitch * h), p);
}
-void ASurface::moveBufferDown() {
+void BaseSurface::moveBufferDown() {
byte *p = (byte *)getPixels();
Common::copy_backward(p, p + (pitch * (h - TILE_HEIGHT)), p + (pitch * h));
}
+bool BaseSurface::clip(Common::Rect &r) {
+ int skip;
+ _leftSkip = _rightSkip = 0;
+ _topSkip = _bottomSkip = 0;
+
+ if (r.left > _clipWidth || r.left < 0) {
+ if (r.left >= 0)
+ return true;
+
+ skip = -r.left;
+ r.setWidth(r.width() - skip);
+ _leftSkip = skip;
+ r.moveTo(0, r.top);
+ }
+
+ int right = r.right - 1;
+ if (right < 0)
+ return true;
+ else if (right > _clipWidth) {
+ skip = right - _clipWidth;
+ r.setWidth(r.width() - skip);
+ _rightSkip = skip;
+ }
+
+ if (r.top > _clipHeight || r.top < 0) {
+ if (r.top >= 0)
+ return true;
+
+ skip = -r.top;
+ r.setHeight(r.height() - skip);
+ _topSkip = skip;
+ r.moveTo(r.left, 0);
+ }
+
+ int bottom = r.bottom - 1;
+ if (bottom < 0)
+ return true;
+ else if (bottom > _clipHeight) {
+ skip = bottom - _clipHeight;
+ _bottomSkip = skip;
+ r.setHeight(r.height() - skip);
+ }
+
+ return false;
+}
+
} // End of namespace Access
diff --git a/engines/access/asurface.h b/engines/access/asurface.h
index dd05c8067b..64ddf3d0ee 100644
--- a/engines/access/asurface.h
+++ b/engines/access/asurface.h
@@ -27,7 +27,7 @@
#include "common/array.h"
#include "common/memstream.h"
#include "common/rect.h"
-#include "graphics/surface.h"
+#include "graphics/screen.h"
#include "access/data.h"
namespace Access {
@@ -35,11 +35,16 @@ namespace Access {
class SpriteResource;
class SpriteFrame;
-class ASurface : public Graphics::Surface {
+/**
+ * Base Access surface class. This derivces from Graphics::Screen
+ * because it has logic we'll need for our own Screen class that
+ * derives from this one
+ */
+class BaseSurface : virtual public Graphics::Screen {
private:
Graphics::Surface _savedBlock;
- void flipHorizontal(ASurface &dest);
+ void flipHorizontal(BaseSurface &dest);
protected:
Common::Rect _savedBounds;
public:
@@ -57,18 +62,12 @@ public:
public:
static int _clipWidth, _clipHeight;
public:
- ASurface();
-
- virtual ~ASurface();
-
- void create(uint16 width, uint16 height);
+ BaseSurface();
- bool empty() const { return w == 0 || h == 0 || pixels == nullptr; }
+ virtual ~BaseSurface();
void clearBuffer();
- bool clip(Common::Rect &r);
-
void plotImage(SpriteResource *sprite, int frameNum, const Common::Point &pt);
/**
@@ -91,7 +90,7 @@ public:
*/
void plotB(SpriteFrame *frame, const Common::Point &pt);
- virtual void copyBlock(ASurface *src, const Common::Rect &bounds);
+ virtual void copyBlock(BaseSurface *src, const Common::Rect &bounds);
virtual void restoreBlock();
@@ -102,20 +101,10 @@ public:
virtual void drawLine();
virtual void drawBox();
-
- virtual void transBlitFrom(ASurface *src, const Common::Point &destPos);
- virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds);
-
- virtual void transBlitFrom(ASurface &src);
-
- virtual void blitFrom(const Graphics::Surface &src);
-
- virtual void copyBuffer(Graphics::Surface *src);
-
- virtual void addDirtyRect(const Common::Rect &r) {}
+ virtual void copyBuffer(Graphics::ManagedSurface *src);
- void copyTo(ASurface *dest);
+ void copyTo(BaseSurface *dest);
void saveBlock(const Common::Rect &bounds);
@@ -126,6 +115,19 @@ public:
void moveBufferUp();
void moveBufferDown();
+
+ bool clip(Common::Rect &r);
+};
+
+class ASurface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ ASurface() : BaseSurface() {}
};
class SpriteFrame : public ASurface {
diff --git a/engines/access/bubble_box.cpp b/engines/access/bubble_box.cpp
index ef32e96f59..29b58a3f1b 100644
--- a/engines/access/bubble_box.cpp
+++ b/engines/access/bubble_box.cpp
@@ -165,7 +165,7 @@ void BubbleBox::printBubble(const Common::String &msg) {
void BubbleBox::printBubble_v1(const Common::String &msg) {
drawBubble(_bubbles.size() - 1);
-
+
// Loop through drawing the lines
Common::String s = msg;
Common::String line;
@@ -228,7 +228,7 @@ void BubbleBox::drawBubble(int index) {
void BubbleBox::doBox(int item, int box) {
FontManager &fonts = _vm->_fonts;
- ASurface &screen = *_vm->_screen;
+ Screen &screen = *_vm->_screen;
_startItem = item;
_startBox = box;
@@ -369,7 +369,7 @@ void BubbleBox::displayBoxData() {
_vm->_screen->drawRect();
_vm->_events->showCursor();
}
-
+
_vm->_events->hideCursor();
int oldPStartY = _boxPStartY;
++_boxPStartY;
@@ -474,7 +474,7 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
--_vm->_screen->_orgX2;
--_vm->_screen->_orgY2;
_vm->_screen->_lColor = 0xF9;
-
+
// Draw the inner border
_vm->_screen->drawBox();
@@ -611,6 +611,7 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
_vm->_events->showCursor();
warning("TODO: pop values");
_vm->_screen->restoreScreen();
+ delete icons;
return retval_;
}
@@ -642,7 +643,9 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
}
}
}
-
+
+ delete icons;
+
_vm->_screen->restoreScreen();
_vm->_boxDataStart = _startItem;
_vm->_boxSelectYOld = -1;
@@ -732,7 +735,7 @@ int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
if (_type != TYPE_3)
continue;
-
+
if ((_vm->_events->_mousePos.x < tmpX) || (_vm->_events->_mousePos.x > tmpX + 144))
continue;
diff --git a/engines/access/char.cpp b/engines/access/char.cpp
index cbe1d5d3d9..f6d3033b1b 100644
--- a/engines/access/char.cpp
+++ b/engines/access/char.cpp
@@ -44,7 +44,7 @@ CharEntry::CharEntry(const byte *data, AccessEngine *vm) {
if (vm->getGameID() == GType_MartianMemorandum) {
int lastColor = s.readUint16LE();
_numColors = lastColor - _startColor;
- } else
+ } else
_numColors = s.readUint16LE();
// Load cells
@@ -131,6 +131,7 @@ void CharManager::loadChar(int charId) {
if (ce._animFile._fileNum != -1) {
Resource *data = _vm->_files->loadFile(ce._animFile);
_vm->_animation->loadAnimations(data);
+ delete data;
}
// Load script data
diff --git a/engines/access/detection.cpp b/engines/access/detection.cpp
index 2cd7e50f0f..368753f117 100644
--- a/engines/access/detection.cpp
+++ b/engines/access/detection.cpp
@@ -94,7 +94,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Access Engine (c) 1989-1994 Access Software";
+ return "Access Engine (C) 1989-1994 Access Software";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/access/detection_tables.h b/engines/access/detection_tables.h
index 9556cd9f67..7d9509ca43 100644
--- a/engines/access/detection_tables.h
+++ b/engines/access/detection_tables.h
@@ -49,7 +49,7 @@ static const AccessGameDescription gameDescriptions[] = {
AD_ENTRY1s("c00.ap", "aeb429ff015596144c0df06886c84825", 303753),
Common::ES_ESP,
Common::kPlatformDOS,
- ADGF_NO_FLAGS,
+ ADGF_UNSTABLE,
GUIO1(GUIO_NONE)
},
GType_Amazon,
diff --git a/engines/access/events.cpp b/engines/access/events.cpp
index d62b05c33f..21ff0d0928 100644
--- a/engines/access/events.cpp
+++ b/engines/access/events.cpp
@@ -115,7 +115,7 @@ void EventsManager::setCursor(CursorType cursorId) {
}
}
-void EventsManager::setCursorData(Graphics::Surface *src, const Common::Rect &r) {
+void EventsManager::setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r) {
_invCursor.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8());
_invCursor.copyRectToSurface(*src, 0, 0, r);
}
@@ -281,8 +281,7 @@ void EventsManager::nextFrame() {
// Give time to the debugger
_vm->_debugger->onFrame();
- // TODO: Refactor for dirty rects
- _vm->_screen->updateScreen();
+ _vm->_screen->update();
}
void EventsManager::nextTimer() {
diff --git a/engines/access/events.h b/engines/access/events.h
index b8c5f0ee5e..5acbb71c9d 100644
--- a/engines/access/events.h
+++ b/engines/access/events.h
@@ -100,7 +100,7 @@ public:
/**
* Set the image for the inventory cursor
*/
- void setCursorData(Graphics::Surface *src, const Common::Rect &r);
+ void setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r);
/**
* Return the current cursor Id
diff --git a/engines/access/files.cpp b/engines/access/files.cpp
index b9c0f7080d..48276ee477 100644
--- a/engines/access/files.cpp
+++ b/engines/access/files.cpp
@@ -130,13 +130,13 @@ void FileManager::openFile(Resource *res, const Common::String &filename) {
error("Could not open file - %s", filename.c_str());
}
-void FileManager::loadScreen(Graphics::Surface *dest, int fileNum, int subfile) {
+void FileManager::loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile) {
Resource *res = loadFile(fileNum, subfile);
handleScreen(dest, res);
delete res;
}
-void FileManager::handleScreen(Graphics::Surface *dest, Resource *res) {
+void FileManager::handleScreen(Graphics::ManagedSurface *dest, Resource *res) {
_vm->_screen->loadRawPalette(res->_stream);
if (_setPaletteFlag)
_vm->_screen->setPalette();
@@ -147,20 +147,17 @@ void FileManager::handleScreen(Graphics::Surface *dest, Resource *res) {
res->_size -= res->_stream->pos();
handleFile(res);
- if (dest != _vm->_screen)
- dest->w = _vm->_screen->w;
+ Graphics::Surface destSurface = dest->getSubArea(Common::Rect(0, 0,
+ _vm->_screen->w, _vm->_screen->h));
- if (dest->w == dest->pitch) {
- res->_stream->read((byte *)dest->getPixels(), dest->w * dest->h);
+ if (destSurface.w == destSurface.pitch) {
+ res->_stream->read((byte *)destSurface.getPixels(), destSurface.w * destSurface.h);
} else {
- for (int y = 0; y < dest->h; ++y) {
- byte *pDest = (byte *)dest->getBasePtr(0, y);
- res->_stream->read(pDest, dest->w);
+ for (int y = 0; y < destSurface.h; ++y) {
+ byte *pDest = (byte *)destSurface.getBasePtr(0, y);
+ res->_stream->read(pDest, destSurface.w);
}
}
-
- if (dest == _vm->_screen)
- _vm->_screen->addDirtyRect(Common::Rect(0, 0, dest->w, dest->h));
}
void FileManager::loadScreen(int fileNum, int subfile) {
diff --git a/engines/access/files.h b/engines/access/files.h
index d081934e91..61fccc2431 100644
--- a/engines/access/files.h
+++ b/engines/access/files.h
@@ -26,7 +26,7 @@
#include "common/scummsys.h"
#include "common/array.h"
#include "common/file.h"
-#include "graphics/surface.h"
+#include "graphics/managed_surface.h"
#include "access/decompress.h"
namespace Access {
@@ -81,7 +81,7 @@ private:
/**
* Handles loading a screen surface and palette with decoded resource
*/
- void handleScreen(Graphics::Surface *dest, Resource *res);
+ void handleScreen(Graphics::ManagedSurface *dest, Resource *res);
/**
* Open up a sub-file container file
@@ -133,7 +133,7 @@ public:
/**
* Load a screen resource onto a designated surface
*/
- void loadScreen(Graphics::Surface *dest, int fileNum, int subfile);
+ void loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile);
};
} // End of namespace Access
diff --git a/engines/access/font.cpp b/engines/access/font.cpp
index 8af183f193..8e02f80769 100644
--- a/engines/access/font.cpp
+++ b/engines/access/font.cpp
@@ -139,7 +139,7 @@ bool Font::getLine(Common::String &s, int maxWidth, Common::String &line, int &w
return true;
}
-void Font::drawString(ASurface *s, const Common::String &msg, const Common::Point &pt) {
+void Font::drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt) {
Common::Point currPt = pt;
const char *msgP = msg.c_str();
@@ -149,15 +149,14 @@ void Font::drawString(ASurface *s, const Common::String &msg, const Common::Poin
}
}
-int Font::drawChar(ASurface *s, char c, Common::Point &pt) {
+int Font::drawChar(BaseSurface *s, char c, Common::Point &pt) {
Graphics::Surface &ch = _chars[c - ' '];
-
- s->addDirtyRect(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h));
+ Graphics::Surface dest = s->getSubArea(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h));
// Loop through the lines of the character
for (int y = 0; y < ch.h; ++y) {
byte *pSrc = (byte *)ch.getBasePtr(0, y);
- byte *pDest = (byte *)s->getBasePtr(pt.x, pt.y + y);
+ byte *pDest = (byte *)dest.getBasePtr(0, y);
// Loop through the horizontal pixels of the line
for (int x = 0; x < ch.w; ++x, ++pSrc, ++pDest) {
diff --git a/engines/access/font.h b/engines/access/font.h
index 6a812051ca..9234078af2 100644
--- a/engines/access/font.h
+++ b/engines/access/font.h
@@ -78,12 +78,12 @@ public:
/**
* Draw a string on a given surface
*/
- void drawString(ASurface *s, const Common::String &msg, const Common::Point &pt);
+ void drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt);
/**
* Draw a character on a given surface
*/
- int drawChar(ASurface *s, char c, Common::Point &pt);
+ int drawChar(BaseSurface *s, char c, Common::Point &pt);
};
diff --git a/engines/access/inventory.cpp b/engines/access/inventory.cpp
index 0a962aa69a..e9874cd8d6 100644
--- a/engines/access/inventory.cpp
+++ b/engines/access/inventory.cpp
@@ -223,6 +223,7 @@ int InventoryManager::displayInv() {
else
_vm->_useItem = -1;
+ free(names);
free(inv);
return 0;
}
diff --git a/engines/access/room.cpp b/engines/access/room.cpp
index a7192d330f..a41de63bf6 100644
--- a/engines/access/room.cpp
+++ b/engines/access/room.cpp
@@ -142,7 +142,7 @@ void Room::takePicture() {
_vm->_player->_roomNumber = 7;
_vm->_room->_function = FN_CLEAR1;
return;
- } else if (result >= 0)
+ } else if (result >= 0)
_vm->_player->_move = (Direction)(result + 1);
_vm->_player->_scrollFlag = false;
@@ -715,6 +715,8 @@ void Room::executeCommand(int commandId) {
screen.plotImage(spr, _selectCommand + 2,
Common::Point(_rMouse[_selectCommand][0], (_vm->getGameID() == GType_MartianMemorandum) ? 184 : 176));
+ delete spr;
+
_vm->_screen->restoreScreen();
_vm->_boxSelect = true;
}
diff --git a/engines/access/screen.cpp b/engines/access/screen.cpp
index aa15abd59a..2d29ad0718 100644
--- a/engines/access/screen.cpp
+++ b/engines/access/screen.cpp
@@ -69,8 +69,6 @@ void Screen::clearScreen() {
clearBuffer();
if (_vesaMode)
_vm->_clearSummaryFlag = true;
-
- addDirtyRect(Common::Rect(0, 0, this->w, this->h));
}
void Screen::setDisplayScan() {
@@ -89,28 +87,14 @@ void Screen::setPanel(int num) {
_msVirtualOffset = _virtualOffsetsTable[num];
}
-void Screen::updateScreen() {
+void Screen::update() {
if (_vm->_startup >= 0) {
if (--_vm->_startup == -1)
_fadeIn = true;
return;
}
-
- // Merge the dirty rects
- mergeDirtyRects();
-
- // Loop through copying dirty areas to the physical screen
- Common::List<Common::Rect>::iterator i;
- for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) {
- const Common::Rect &r = *i;
- const byte *srcP = (const byte *)getBasePtr(r.left, r.top);
- g_system->copyRectToScreen(srcP, this->pitch, r.left, r.top,
- r.width(), r.height());
- }
-
- // Signal the physical screen to update
- g_system->updateScreen();
- _dirtyRects.clear();
+ markAllDirty();//****DEBUG****
+ Graphics::Screen::update();
}
void Screen::setInitialPalettte() {
@@ -153,7 +137,7 @@ void Screen::loadRawPalette(Common::SeekableReadStream *stream) {
void Screen::updatePalette() {
g_system->getPaletteManager()->setPalette(&_tempPalette[0], 0, PALETTE_COUNT);
- updateScreen();
+ update();
}
void Screen::savePalette() {
@@ -269,7 +253,7 @@ void Screen::restoreScreen() {
_screenYOff = _screenSave._screenYOff;
}
-void Screen::copyBlock(ASurface *src, const Common::Rect &bounds) {
+void Screen::copyBlock(BaseSurface *src, const Common::Rect &bounds) {
Common::Rect destBounds = bounds;
destBounds.translate(_windowXAdd, _windowYAdd + _screenYOff);
@@ -280,37 +264,22 @@ void Screen::copyBlock(ASurface *src, const Common::Rect &bounds) {
void Screen::restoreBlock() {
if (!_savedBounds.isEmpty())
addDirtyRect(_savedBounds);
- ASurface::restoreBlock();
+ BaseSurface::restoreBlock();
}
void Screen::drawRect() {
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
- ASurface::drawRect();
+ BaseSurface::drawRect();
}
void Screen::drawBox() {
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
- ASurface::drawBox();
-}
-
-void Screen::transBlitFrom(ASurface *src, const Common::Point &destPos) {
- addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + src->w, destPos.y + src->h));
- ASurface::transBlitFrom(src, destPos);
+ BaseSurface::drawBox();
}
-void Screen::transBlitFrom(ASurface *src, const Common::Rect &bounds) {
- addDirtyRect(bounds);
- ASurface::transBlitFrom(src, bounds);
-}
-
-void Screen::blitFrom(const Graphics::Surface &src) {
- addDirtyRect(Common::Rect(0, 0, src.w, src.h));
- ASurface::blitFrom(src);
-}
-
-void Screen::copyBuffer(Graphics::Surface *src) {
+void Screen::copyBuffer(Graphics::ManagedSurface *src) {
addDirtyRect(Common::Rect(0, 0, src->w, src->h));
- ASurface::copyBuffer(src);
+ BaseSurface::copyBuffer(src);
}
void Screen::setPaletteCycle(int startCycle, int endCycle, int timer) {
@@ -349,51 +318,7 @@ void Screen::cyclePaletteBackwards() {
}
void Screen::flashPalette(int count) {
- warning("TODO: Implement flashPalette");
-}
-
-void Screen::addDirtyRect(const Common::Rect &r) {
- _dirtyRects.push_back(r);
- assert(r.isValidRect() && r.width() > 0 && r.height() > 0);
-}
-
-void Screen::mergeDirtyRects() {
- Common::List<Common::Rect>::iterator rOuter, rInner;
-
- // Ensure dirty rect list has at least two entries
- rOuter = _dirtyRects.begin();
- for (int i = 0; i < 2; ++i, ++rOuter) {
- if (rOuter == _dirtyRects.end())
- return;
- }
-
- // Process the dirty rect list to find any rects to merge
- for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
- rInner = rOuter;
- while (++rInner != _dirtyRects.end()) {
-
- if ((*rOuter).intersects(*rInner)) {
- // these two rectangles overlap or
- // are next to each other - merge them
-
- unionRectangle(*rOuter, *rOuter, *rInner);
-
- // remove the inner rect from the list
- _dirtyRects.erase(rInner);
-
- // move back to beginning of list
- rInner = rOuter;
- }
- }
- }
+ // No implementation needed in ScummVM
}
-bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) {
- destRect = src1;
- destRect.extend(src2);
-
- return !destRect.isEmpty();
-}
-
-
} // End of namespace Access
diff --git a/engines/access/screen.h b/engines/access/screen.h
index 6fa0fe3812..1c1932511d 100644
--- a/engines/access/screen.h
+++ b/engines/access/screen.h
@@ -26,15 +26,13 @@
#include "common/scummsys.h"
#include "common/rect.h"
#include "common/stream.h"
+#include "graphics/screen.h"
#include "access/asurface.h"
namespace Access {
class AccessEngine;
-#define PALETTE_COUNT 256
-#define PALETTE_SIZE (256 * 3)
-
struct ScreenSave {
int _clipWidth;
int _clipHeight;
@@ -47,7 +45,7 @@ struct ScreenSave {
int _screenYOff;
};
-class Screen : public ASurface {
+class Screen : public BaseSurface {
private:
AccessEngine *_vm;
byte _tempPalette[PALETTE_SIZE];
@@ -66,10 +64,6 @@ private:
Common::List<Common::Rect> _dirtyRects;
void updatePalette();
-
- void mergeDirtyRects();
-
- bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
public:
int _vesaMode;
int _startColor, _numColors;
@@ -87,7 +81,12 @@ public:
bool _screenChangeFlag;
bool _fadeIn;
public:
- virtual void copyBlock(ASurface *src, const Common::Rect &bounds);
+ /**
+ * Updates the screen
+ */
+ virtual void update();
+
+ virtual void copyBlock(BaseSurface *src, const Common::Rect &bounds);
virtual void restoreBlock();
@@ -95,15 +94,7 @@ public:
virtual void drawBox();
- virtual void transBlitFrom(ASurface *src, const Common::Point &destPos);
-
- virtual void transBlitFrom(ASurface *src, const Common::Rect &bounds);
-
- virtual void blitFrom(const Graphics::Surface &src);
-
- virtual void copyBuffer(Graphics::Surface *src);
-
- virtual void addDirtyRect(const Common::Rect &r);
+ virtual void copyBuffer(Graphics::ManagedSurface *src);
public:
Screen(AccessEngine *vm);
@@ -114,11 +105,6 @@ public:
void setPanel(int num);
/**
- * Update the underlying screen
- */
- void updateScreen();
-
- /**
* Fade out screen
*/
void forceFadeOut();
diff --git a/engines/access/sound.cpp b/engines/access/sound.cpp
index 38f544de4e..cf52bc58c5 100644
--- a/engines/access/sound.cpp
+++ b/engines/access/sound.cpp
@@ -20,9 +20,11 @@
*
*/
-#include "common/algorithm.h"
#include "common/config-manager.h"
#include "audio/mixer.h"
+#include "audio/audiostream.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
// Miles Audio
@@ -33,10 +35,12 @@
namespace Access {
SoundManager::SoundManager(AccessEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
+ _effectsHandle = new Audio::SoundHandle();
}
SoundManager::~SoundManager() {
clearSounds();
+ delete _effectsHandle;
}
void SoundManager::clearSounds() {
@@ -47,8 +51,8 @@ void SoundManager::clearSounds() {
_soundTable.clear();
- if (_mixer->isSoundHandleActive(_effectsHandle))
- _mixer->stopHandle(_effectsHandle);
+ if (_mixer->isSoundHandleActive(*_effectsHandle))
+ _mixer->stopHandle(*_effectsHandle);
while (_queue.size()) {
delete _queue[0]._stream;
@@ -157,8 +161,8 @@ void SoundManager::playSound(Resource *res, int priority, bool loop, int soundIn
_queue.push_back(QueuedSound(audioStream, soundIndex));
}
- if (!_mixer->isSoundHandleActive(_effectsHandle))
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
+ if (!_mixer->isSoundHandleActive(*_effectsHandle))
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _effectsHandle,
_queue[0]._stream, -1, _mixer->kMaxChannelVolume, 0,
DisposeAfterUse::NO);
}
@@ -166,20 +170,20 @@ void SoundManager::playSound(Resource *res, int priority, bool loop, int soundIn
void SoundManager::checkSoundQueue() {
debugC(5, kDebugSound, "checkSoundQueue");
- if (_queue.empty() || _mixer->isSoundHandleActive(_effectsHandle))
+ if (_queue.empty() || _mixer->isSoundHandleActive(*_effectsHandle))
return;
delete _queue[0]._stream;
_queue.remove_at(0);
if (_queue.size() && _queue[0]._stream)
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_effectsHandle,
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _effectsHandle,
_queue[0]._stream, -1, _mixer->kMaxChannelVolume, 0,
DisposeAfterUse::NO);
}
bool SoundManager::isSFXPlaying() {
- return _mixer->isSoundHandleActive(_effectsHandle);
+ return _mixer->isSoundHandleActive(*_effectsHandle);
}
void SoundManager::loadSounds(Common::Array<RoomInfo::SoundIdent> &sounds) {
@@ -196,7 +200,7 @@ void SoundManager::loadSounds(Common::Array<RoomInfo::SoundIdent> &sounds) {
void SoundManager::stopSound() {
debugC(3, kDebugSound, "stopSound");
- _mixer->stopHandle(_effectsHandle);
+ _mixer->stopHandle(*_effectsHandle);
}
void SoundManager::freeSounds() {
diff --git a/engines/access/sound.h b/engines/access/sound.h
index b372e566d2..d75540dd13 100644
--- a/engines/access/sound.h
+++ b/engines/access/sound.h
@@ -24,14 +24,16 @@
#define ACCESS_SOUND_H
#include "common/scummsys.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
#include "access/files.h"
#include "audio/midiplayer.h"
-#include "audio/midiparser.h"
#define MAX_SOUNDS 20
+namespace Audio {
+class AudioStream;
+class SoundHandle;
+}
+
namespace Access {
class AccessEngine;
@@ -55,7 +57,7 @@ class SoundManager {
private:
AccessEngine *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _effectsHandle;
+ Audio::SoundHandle *_effectsHandle;
Common::Array<QueuedSound> _queue;
void clearSounds();
diff --git a/engines/access/video.cpp b/engines/access/video.cpp
index 5fc5f6762c..22842a5855 100644
--- a/engines/access/video.cpp
+++ b/engines/access/video.cpp
@@ -48,7 +48,7 @@ VideoPlayer::~VideoPlayer() {
closeVideo();
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate) {
_vidSurface = vidSurface;
vidSurface->_orgX1 = pt.x;
vidSurface->_orgY1 = pt.y;
@@ -87,14 +87,14 @@ void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, int ra
_videoEnd = false;
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate) {
// Open up video stream
_videoData = _vm->_files->loadFile(filename);
setVideo(vidSurface, pt, rate);
}
-void VideoPlayer::setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
+void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
// Open up video stream
_videoData = _vm->_files->loadFile(videoFile);
@@ -157,7 +157,7 @@ void VideoPlayer::playVideo() {
// If the video is playing on the screen surface, add a dirty rect
if (_vidSurface == _vm->_screen)
- _vm->_screen->addDirtyRect(_videoBounds);
+ _vm->_screen->markAllDirty();
getFrame();
if (++_videoFrame == _frameCount) {
diff --git a/engines/access/video.h b/engines/access/video.h
index 83c8995d3e..65dff3ebea 100644
--- a/engines/access/video.h
+++ b/engines/access/video.h
@@ -40,7 +40,7 @@ class VideoPlayer : public Manager {
VideoFlags _flags;
};
private:
- ASurface *_vidSurface;
+ BaseSurface *_vidSurface;
Resource *_videoData;
VideoHeader _header;
byte *_startCoord;
@@ -51,7 +51,7 @@ private:
Common::Rect _videoBounds;
void getFrame();
- void setVideo(ASurface *vidSurface, const Common::Point &pt, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate);
public:
int _videoFrame;
bool _soundFlag;
@@ -64,8 +64,8 @@ public:
/**
* Start up a video
*/
- void setVideo(ASurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
- void setVideo(ASurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
+ void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::String filename, int rate);
/**
* Decodes a frame of the video
diff --git a/engines/access/video/movie_decoder.cpp b/engines/access/video/movie_decoder.cpp
index 05ec25d54c..1406e549ad 100644
--- a/engines/access/video/movie_decoder.cpp
+++ b/engines/access/video/movie_decoder.cpp
@@ -719,7 +719,7 @@ bool AccessEngine::playMovie(const Common::String &filename, const Common::Point
g_system->getPaletteManager()->setPalette(palette, 0, 256);
}
- _screen->updateScreen();
+ _screen->update();
}
}
diff --git a/engines/access/video/movie_decoder.h b/engines/access/video/movie_decoder.h
index fe8a89fcde..8b5d94836b 100644
--- a/engines/access/video/movie_decoder.h
+++ b/engines/access/video/movie_decoder.h
@@ -23,13 +23,8 @@
#ifndef ACCESS_VIDEO_MOVIE_DECODER_H
#define ACCESS_VIDEO_MOVIE_DECODER_H
-#include "common/rect.h"
#include "video/video_decoder.h"
-#include "audio/decoders/raw.h"
-
-namespace Audio {
-class QueuingAudioStream;
-}
+#include "audio/audiostream.h"
namespace Common {
class SeekableReadStream;
diff --git a/engines/adl/POTFILES b/engines/adl/POTFILES
new file mode 100644
index 0000000000..ca485932f7
--- /dev/null
+++ b/engines/adl/POTFILES
@@ -0,0 +1 @@
+engines/adl/detection.cpp
diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
new file mode 100644
index 0000000000..b6af54962e
--- /dev/null
+++ b/engines/adl/adl.cpp
@@ -0,0 +1,1316 @@
+/* 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.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/error.h"
+#include "common/file.h"
+#include "common/system.h"
+#include "common/events.h"
+#include "common/stream.h"
+#include "common/savefile.h"
+
+#include "engines/util.h"
+
+#include "graphics/palette.h"
+#include "graphics/thumbnail.h"
+
+#include "adl/adl.h"
+#include "adl/display.h"
+#include "adl/detection.h"
+#include "adl/graphics.h"
+#include "adl/speaker.h"
+
+namespace Adl {
+
+AdlEngine::~AdlEngine() {
+ delete _display;
+ delete _graphics;
+ delete _speaker;
+ delete _console;
+ delete _dumpFile;
+}
+
+AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) :
+ Engine(syst),
+ _dumpFile(nullptr),
+ _display(nullptr),
+ _graphics(nullptr),
+ _isRestarting(false),
+ _isRestoring(false),
+ _skipOneCommand(false),
+ _gameDescription(gd),
+ _saveVerb(0),
+ _saveNoun(0),
+ _restoreVerb(0),
+ _restoreNoun(0),
+ _canSaveNow(false),
+ _canRestoreNow(false) {
+
+ DebugMan.addDebugChannel(kDebugChannelScript, "Script", "Trace script execution");
+}
+
+bool AdlEngine::pollEvent(Common::Event &event) const {
+ _console->onFrame();
+
+ if (g_system->getEventManager()->pollEvent(event)) {
+ if (event.type != Common::EVENT_KEYDOWN)
+ return false;
+
+ if (event.kbd.flags & Common::KBD_CTRL) {
+ if (event.kbd.keycode == Common::KEYCODE_q) {
+ quitGame();
+ return false;
+ }
+
+ if (event.kbd.keycode == Common::KEYCODE_d) {
+ _console->attach();
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+Common::String AdlEngine::readString(Common::ReadStream &stream, byte until) const {
+ Common::String str;
+
+ while (1) {
+ byte b = stream.readByte();
+
+ if (stream.eos() || stream.err())
+ error("Error reading string");
+
+ if (b == until)
+ break;
+
+ str += b;
+ };
+
+ return str;
+}
+
+Common::String AdlEngine::readStringAt(Common::SeekableReadStream &stream, uint offset, byte until) const {
+ stream.seek(offset);
+ return readString(stream, until);
+}
+
+void AdlEngine::openFile(Common::File &file, const Common::String &name) const {
+ if (!file.open(name))
+ error("Error opening '%s'", name.c_str());
+}
+
+void AdlEngine::printMessage(uint idx) {
+ printString(loadMessage(idx));
+}
+
+Common::String AdlEngine::getItemDescription(const Item &item) const {
+ if (item.description > 0)
+ return loadMessage(item.description);
+ else
+ return Common::String();
+}
+
+void AdlEngine::delay(uint32 ms) const {
+ uint32 start = g_system->getMillis();
+
+ while (!shouldQuit() && g_system->getMillis() - start < ms) {
+ Common::Event event;
+ pollEvent(event);
+ g_system->delayMillis(16);
+ }
+}
+
+Common::String AdlEngine::inputString(byte prompt) const {
+ Common::String s;
+
+ if (prompt > 0)
+ _display->printString(Common::String(prompt));
+
+ while (1) {
+ byte b = inputKey();
+
+ if (shouldQuit() || _isRestoring)
+ return 0;
+
+ if (b == 0)
+ continue;
+
+ if (b == ('\r' | 0x80)) {
+ s += b;
+ _display->printString(Common::String(b));
+ return s;
+ }
+
+ if (b < 0xa0) {
+ switch (b) {
+ case Common::KEYCODE_BACKSPACE | 0x80:
+ if (!s.empty()) {
+ _display->moveCursorBackward();
+ _display->setCharAtCursor(APPLECHAR(' '));
+ s.deleteLastChar();
+ }
+ break;
+ };
+ } else {
+ if (s.size() < 255) {
+ s += b;
+ _display->printString(Common::String(b));
+ }
+ }
+ }
+}
+
+byte AdlEngine::inputKey(bool showCursor) const {
+ byte key = 0;
+
+ if (showCursor)
+ _display->showCursor(true);
+
+ while (!shouldQuit() && !_isRestoring && key == 0) {
+ Common::Event event;
+ if (pollEvent(event)) {
+ if (event.type != Common::EVENT_KEYDOWN)
+ continue;
+
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_BACKSPACE:
+ case Common::KEYCODE_RETURN:
+ key = convertKey(event.kbd.keycode);
+ break;
+ default:
+ if (event.kbd.ascii >= 0x20 && event.kbd.ascii < 0x80)
+ key = convertKey(event.kbd.ascii);
+ };
+ }
+
+ _display->updateTextScreen();
+ g_system->delayMillis(16);
+ }
+
+ _display->showCursor(false);
+
+ return key;
+}
+
+void AdlEngine::loadWords(Common::ReadStream &stream, WordMap &map, Common::StringArray &pri) const {
+ uint index = 0;
+
+ map.clear();
+ pri.clear();
+
+ while (1) {
+ ++index;
+
+ byte buf[IDI_WORD_SIZE];
+
+ if (stream.read(buf, IDI_WORD_SIZE) < IDI_WORD_SIZE)
+ error("Error reading word list");
+
+ Common::String word((char *)buf, IDI_WORD_SIZE);
+
+ if (!map.contains(word))
+ map[word] = index;
+
+ pri.push_back(Console::toAscii(word));
+
+ byte synonyms = stream.readByte();
+
+ if (stream.err() || stream.eos())
+ error("Error reading word list");
+
+ if (synonyms == 0xff)
+ break;
+
+ for (uint i = 0; i < synonyms; ++i) {
+ if (stream.read((char *)buf, IDI_WORD_SIZE) < IDI_WORD_SIZE)
+ error("Error reading word list");
+
+ word = Common::String((char *)buf, IDI_WORD_SIZE);
+
+ if (!map.contains(word))
+ map[word] = index;
+ }
+ }
+}
+
+void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) {
+ commands.clear();
+
+ while (1) {
+ Command command;
+ command.room = stream.readByte();
+
+ if (command.room == 0xff)
+ return;
+
+ command.verb = stream.readByte();
+ command.noun = stream.readByte();
+
+ byte scriptSize = stream.readByte() - 6;
+
+ command.numCond = stream.readByte();
+ command.numAct = stream.readByte();
+
+ for (uint i = 0; i < scriptSize; ++i)
+ command.script.push_back(stream.readByte());
+
+ if (stream.eos() || stream.err())
+ error("Failed to read commands");
+
+ if (command.numCond == 0 && command.script[0] == IDO_ACT_SAVE) {
+ _saveVerb = command.verb;
+ _saveNoun = command.noun;
+ }
+
+ if (command.numCond == 0 && command.script[0] == IDO_ACT_LOAD) {
+ _restoreVerb = command.verb;
+ _restoreNoun = command.noun;
+ }
+
+ commands.push_back(command);
+ }
+}
+
+void AdlEngine::checkInput(byte verb, byte noun) {
+ // Try room-local command list first
+ if (doOneCommand(_roomData.commands, verb, noun))
+ return;
+
+ // If no match was found, try the global list
+ if (!doOneCommand(_roomCommands, verb, noun))
+ printMessage(_messageIds.dontUnderstand);
+}
+
+bool AdlEngine::isInputValid(byte verb, byte noun, bool &is_any) {
+ if (isInputValid(_roomData.commands, verb, noun, is_any))
+ return true;
+ return isInputValid(_roomCommands, verb, noun, is_any);
+}
+
+bool AdlEngine::isInputValid(const Commands &commands, byte verb, byte noun, bool &is_any) {
+ Commands::const_iterator cmd;
+
+ is_any = false;
+ for (cmd = commands.begin(); cmd != commands.end(); ++cmd) {
+ ScriptEnv env(*cmd, _state.room, verb, noun);
+ if (matchCommand(env)) {
+ if (cmd->verb == IDI_ANY || cmd->noun == IDI_ANY)
+ is_any = true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine> OpcodeV1;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV1(this, &AdlEngine::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV1(this, 0))
+
+void AdlEngine::setupOpcodeTables() {
+ Common::Array<const Opcode *> *table = 0;
+
+ SetOpcodeTable(_condOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(o1_isItemInRoom);
+ // 0x04
+ OpcodeUnImpl();
+ Opcode(o1_isMovesGT);
+ Opcode(o1_isVarEQ);
+ OpcodeUnImpl();
+ // 0x08
+ OpcodeUnImpl();
+ Opcode(o1_isCurPicEQ);
+ Opcode(o1_isItemPicEQ);
+
+ SetOpcodeTable(_actOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o1_varAdd);
+ Opcode(o1_varSub);
+ Opcode(o1_varSet);
+ // 0x04
+ Opcode(o1_listInv);
+ Opcode(o1_moveItem);
+ Opcode(o1_setRoom);
+ Opcode(o1_setCurPic);
+ // 0x08
+ Opcode(o1_setPic);
+ Opcode(o1_printMsg);
+ Opcode(o1_setLight);
+ Opcode(o1_setDark);
+ // 0x0c
+ OpcodeUnImpl();
+ Opcode(o1_quit);
+ OpcodeUnImpl();
+ Opcode(o1_save);
+ // 0x10
+ Opcode(o1_restore);
+ Opcode(o1_restart);
+ Opcode(o1_placeItem);
+ Opcode(o1_setItemPic);
+ // 0x14
+ Opcode(o1_resetPic);
+ Opcode(o1_goDirection<IDI_DIR_NORTH>);
+ Opcode(o1_goDirection<IDI_DIR_SOUTH>);
+ Opcode(o1_goDirection<IDI_DIR_EAST>);
+ // 0x18
+ Opcode(o1_goDirection<IDI_DIR_WEST>);
+ Opcode(o1_goDirection<IDI_DIR_UP>);
+ Opcode(o1_goDirection<IDI_DIR_DOWN>);
+ Opcode(o1_takeItem);
+ // 0x1c
+ Opcode(o1_dropItem);
+ Opcode(o1_setRoomPic);
+}
+
+void AdlEngine::initState() {
+ _state = State();
+
+ initGameState();
+}
+
+byte AdlEngine::roomArg(byte room) const {
+ return room;
+}
+
+void AdlEngine::clearScreen() const {
+ _display->setMode(DISPLAY_MODE_MIXED);
+ _display->clear(0x00);
+}
+
+void AdlEngine::drawPic(byte pic, Common::Point pos) const {
+ if (_roomData.pictures.contains(pic))
+ _graphics->drawPic(*_roomData.pictures[pic]->createReadStream(), pos);
+ else
+ _graphics->drawPic(*_pictures[pic]->createReadStream(), pos);
+}
+
+void AdlEngine::bell(uint count) const {
+ _speaker->bell(count);
+}
+
+const Room &AdlEngine::getRoom(uint i) const {
+ if (i < 1 || i > _state.rooms.size())
+ error("Room %i out of range [1, %i]", i, _state.rooms.size());
+
+ return _state.rooms[i - 1];
+}
+
+Room &AdlEngine::getRoom(uint i) {
+ if (i < 1 || i > _state.rooms.size())
+ error("Room %i out of range [1, %i]", i, _state.rooms.size());
+
+ return _state.rooms[i - 1];
+}
+
+const Room &AdlEngine::getCurRoom() const {
+ return getRoom(_state.room);
+}
+
+Room &AdlEngine::getCurRoom() {
+ return getRoom(_state.room);
+}
+
+const Item &AdlEngine::getItem(uint i) const {
+ Common::List<Item>::const_iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->id == i)
+ return *item;
+
+ error("Item %i not found", i);
+}
+
+Item &AdlEngine::getItem(uint i) {
+ Common::List<Item>::iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->id == i)
+ return *item;
+
+ error("Item %i not found", i);
+}
+
+byte AdlEngine::getVar(uint i) const {
+ if (i >= _state.vars.size())
+ error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1);
+
+ return _state.vars[i];
+}
+
+void AdlEngine::setVar(uint i, byte value) {
+ if (i >= _state.vars.size())
+ error("Variable %i out of range [0, %i]", i, _state.vars.size() - 1);
+
+ _state.vars[i] = value;
+}
+
+void AdlEngine::takeItem(byte noun) {
+ Common::List<Item>::iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ if (item->noun != noun || item->room != _state.room)
+ continue;
+
+ if (item->state == IDI_ITEM_DOESNT_MOVE) {
+ printMessage(_messageIds.itemDoesntMove);
+ return;
+ }
+
+ if (item->state == IDI_ITEM_DROPPED) {
+ item->room = IDI_ANY;
+ return;
+ }
+
+ Common::Array<byte>::const_iterator pic;
+ for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) {
+ if (*pic == getCurRoom().curPicture) {
+ item->room = IDI_ANY;
+ item->state = IDI_ITEM_DROPPED;
+ return;
+ }
+ }
+ }
+
+ printMessage(_messageIds.itemNotHere);
+}
+
+void AdlEngine::dropItem(byte noun) {
+ Common::List<Item>::iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ if (item->noun != noun || item->room != IDI_ANY)
+ continue;
+
+ item->room = _state.room;
+ item->state = IDI_ITEM_DROPPED;
+ return;
+ }
+
+ printMessage(_messageIds.dontUnderstand);
+}
+
+Common::Error AdlEngine::run() {
+ _console = new Console(this);
+ _speaker = new Speaker();
+ _display = new Display();
+
+ setupOpcodeTables();
+
+ init();
+
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0) {
+ if (loadGameState(saveSlot).getCode() != Common::kNoError)
+ error("Failed to load save game from slot %i", saveSlot);
+ _display->moveCursorTo(Common::Point(0, 23));
+ _isRestoring = true;
+ } else {
+ runIntro();
+ initState();
+ _display->printAsciiString(_strings.lineFeeds);
+ }
+
+ _display->setMode(DISPLAY_MODE_MIXED);
+
+ while (1) {
+ uint verb = 0, noun = 0;
+ _isRestarting = false;
+
+ // When restoring from the launcher, we don't read
+ // input on the first iteration. This is needed to
+ // ensure that restoring from the launcher and
+ // restoring in-game brings us to the same game state.
+ // (Also see comment below.)
+ if (!_isRestoring) {
+ showRoom();
+
+ if (_isRestarting)
+ continue;
+
+ _canSaveNow = _canRestoreNow = true;
+ getInput(verb, noun);
+ _canSaveNow = _canRestoreNow = false;
+
+ if (shouldQuit())
+ break;
+
+ // If we just restored from the GMM, we skip this command
+ // set, as no command has been input by the user
+ if (!_isRestoring)
+ checkInput(verb, noun);
+ }
+
+ if (_isRestoring) {
+ // We restored from the GMM or launcher. As restoring
+ // with "RESTORE GAME" does not end command processing,
+ // we don't break it off here either. This essentially
+ // means that restoring a game will always run through
+ // the global commands and increase the move counter
+ // before the first user input.
+ _display->printAsciiString("\r");
+ _isRestoring = false;
+ verb = _restoreVerb;
+ noun = _restoreNoun;
+ }
+
+ // Restarting does end command processing
+ if (_isRestarting)
+ continue;
+
+ doAllCommands(_globalCommands, verb, noun);
+
+ if (_isRestarting)
+ continue;
+
+ advanceClock();
+ _state.moves++;
+ }
+
+ return Common::kNoError;
+}
+
+bool AdlEngine::hasFeature(EngineFeature f) const {
+ switch (f) {
+ case kSupportsLoadingDuringRuntime:
+ case kSupportsSavingDuringRuntime:
+ case kSupportsRTL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+Common::Error AdlEngine::loadGameState(int slot) {
+ Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot);
+ Common::InSaveFile *inFile = getSaveFileManager()->openForLoading(fileName);
+
+ if (!inFile) {
+ warning("Failed to open file '%s'", fileName.c_str());
+ return Common::kUnknownError;
+ }
+
+ if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) {
+ warning("No header found in '%s'", fileName.c_str());
+ delete inFile;
+ return Common::kUnknownError;
+ }
+
+ byte saveVersion = inFile->readByte();
+ if (saveVersion != SAVEGAME_VERSION) {
+ warning("Save game version %i not supported", saveVersion);
+ delete inFile;
+ return Common::kUnknownError;
+ }
+
+ // Skip description
+ inFile->seek(SAVEGAME_NAME_LEN, SEEK_CUR);
+ // Skip save time
+ inFile->seek(6, SEEK_CUR);
+
+ uint32 playTime = inFile->readUint32BE();
+
+ Graphics::skipThumbnail(*inFile);
+
+ initState();
+
+ _state.room = inFile->readByte();
+ _state.moves = inFile->readByte();
+ _state.isDark = inFile->readByte();
+ _state.time.hours = inFile->readByte();
+ _state.time.minutes = inFile->readByte();
+
+ uint32 size = inFile->readUint32BE();
+ if (size != _state.rooms.size())
+ error("Room count mismatch (expected %i; found %i)", _state.rooms.size(), size);
+
+ for (uint i = 0; i < size; ++i) {
+ _state.rooms[i].picture = inFile->readByte();
+ _state.rooms[i].curPicture = inFile->readByte();
+ _state.rooms[i].isFirstTime = inFile->readByte();
+ }
+
+ size = inFile->readUint32BE();
+ if (size != _state.items.size())
+ error("Item count mismatch (expected %i; found %i)", _state.items.size(), size);
+
+ Common::List<Item>::iterator item;
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ item->room = inFile->readByte();
+ item->picture = inFile->readByte();
+ item->position.x = inFile->readByte();
+ item->position.y = inFile->readByte();
+ item->state = inFile->readByte();
+ }
+
+ size = inFile->readUint32BE();
+ if (size != _state.vars.size())
+ error("Variable count mismatch (expected %i; found %i)", _state.vars.size(), size);
+
+ for (uint i = 0; i < size; ++i)
+ _state.vars[i] = inFile->readByte();
+
+ if (inFile->err() || inFile->eos())
+ error("Failed to load game '%s'", fileName.c_str());
+
+ delete inFile;
+
+ setTotalPlayTime(playTime);
+
+ _isRestoring = true;
+ return Common::kNoError;
+}
+
+bool AdlEngine::canLoadGameStateCurrently() {
+ return _canRestoreNow;
+}
+
+Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) {
+ Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot);
+ Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName);
+
+ if (!outFile) {
+ warning("Failed to open file '%s'", fileName.c_str());
+ return Common::kUnknownError;
+ }
+
+ outFile->writeUint32BE(MKTAG('A', 'D', 'L', ':'));
+ outFile->writeByte(SAVEGAME_VERSION);
+
+ char name[SAVEGAME_NAME_LEN] = { };
+
+ if (!desc.empty())
+ strncpy(name, desc.c_str(), sizeof(name) - 1);
+ else {
+ Common::String defaultName("Save ");
+ defaultName += 'A' + slot;
+ strncpy(name, defaultName.c_str(), sizeof(name) - 1);
+ }
+
+ outFile->write(name, sizeof(name));
+
+ TimeDate t;
+ g_system->getTimeAndDate(t);
+
+ outFile->writeUint16BE(t.tm_year);
+ outFile->writeByte(t.tm_mon);
+ outFile->writeByte(t.tm_mday);
+ outFile->writeByte(t.tm_hour);
+ outFile->writeByte(t.tm_min);
+
+ uint32 playTime = getTotalPlayTime();
+ outFile->writeUint32BE(playTime);
+
+ _display->saveThumbnail(*outFile);
+
+ outFile->writeByte(_state.room);
+ outFile->writeByte(_state.moves);
+ outFile->writeByte(_state.isDark);
+ outFile->writeByte(_state.time.hours);
+ outFile->writeByte(_state.time.minutes);
+
+ outFile->writeUint32BE(_state.rooms.size());
+ for (uint i = 0; i < _state.rooms.size(); ++i) {
+ outFile->writeByte(_state.rooms[i].picture);
+ outFile->writeByte(_state.rooms[i].curPicture);
+ outFile->writeByte(_state.rooms[i].isFirstTime);
+ }
+
+ outFile->writeUint32BE(_state.items.size());
+ Common::List<Item>::const_iterator item;
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ outFile->writeByte(item->room);
+ outFile->writeByte(item->picture);
+ outFile->writeByte(item->position.x);
+ outFile->writeByte(item->position.y);
+ outFile->writeByte(item->state);
+ }
+
+ outFile->writeUint32BE(_state.vars.size());
+ for (uint i = 0; i < _state.vars.size(); ++i)
+ outFile->writeByte(_state.vars[i]);
+
+ outFile->finalize();
+
+ if (outFile->err()) {
+ delete outFile;
+ warning("Failed to save game '%s'", fileName.c_str());
+ return Common::kUnknownError;
+ }
+
+ delete outFile;
+ return Common::kNoError;
+}
+
+bool AdlEngine::canSaveGameStateCurrently() {
+ if (!_canSaveNow)
+ return false;
+
+ Commands::const_iterator cmd;
+
+ // Here we check whether or not the game currently accepts the command
+ // "SAVE GAME". This prevents saving via the GMM in situations where
+ // it wouldn't otherwise be possible to do so.
+ for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) {
+ ScriptEnv env(*cmd, _state.room, _saveVerb, _saveNoun);
+ if (matchCommand(env))
+ return env.op() == IDO_ACT_SAVE;
+ }
+
+ return false;
+}
+
+byte AdlEngine::convertKey(uint16 ascii) const {
+ ascii = toupper(ascii);
+
+ if (ascii >= 0x80)
+ return 0;
+
+ ascii |= 0x80;
+
+ if (ascii >= 0x80 && ascii <= 0xe0)
+ return ascii;
+
+ return 0;
+}
+
+Common::String AdlEngine::getLine() const {
+ // Original engine uses a global here, which isn't reset between
+ // calls and may not match actual mode
+ bool textMode = false;
+
+ while (1) {
+ Common::String line = inputString(APPLECHAR('?'));
+
+ if (shouldQuit() || _isRestoring)
+ return "";
+
+ if ((byte)line[0] == ('\r' | 0x80)) {
+ textMode = !textMode;
+ _display->setMode(textMode ? DISPLAY_MODE_TEXT : DISPLAY_MODE_MIXED);
+ continue;
+ }
+
+ // Remove the return
+ line.deleteLastChar();
+ return line;
+ }
+}
+
+Common::String AdlEngine::getWord(const Common::String &line, uint &index) const {
+ Common::String str;
+
+ for (uint i = 0; i < 8; ++i)
+ str += APPLECHAR(' ');
+
+ int copied = 0;
+
+ // Skip initial whitespace
+ while (1) {
+ if (index == line.size())
+ return str;
+ if (line[index] != APPLECHAR(' '))
+ break;
+ ++index;
+ }
+
+ // Copy up to 8 characters
+ while (1) {
+ if (copied < 8)
+ str.setChar(line[index], copied++);
+
+ index++;
+
+ if (index == line.size() || line[index] == APPLECHAR(' '))
+ return str;
+ }
+}
+
+Common::String AdlEngine::formatVerbError(const Common::String &verb) const {
+ Common::String err = _strings.verbError;
+ for (uint i = 0; i < verb.size(); ++i)
+ err.setChar(verb[i], i + 19);
+ return err;
+}
+
+Common::String AdlEngine::formatNounError(const Common::String &verb, const Common::String &noun) const {
+ Common::String err = _strings.nounError;
+ for (uint i = 0; i < verb.size(); ++i)
+ err.setChar(verb[i], i + 19);
+ for (uint i = 0; i < noun.size(); ++i)
+ err.setChar(noun[i], i + 30);
+ return err;
+}
+
+void AdlEngine::getInput(uint &verb, uint &noun) {
+ while (1) {
+ _display->printString(_strings.enterCommand);
+ Common::String line = getLine();
+
+ if (shouldQuit() || _isRestoring)
+ return;
+
+ uint index = 0;
+ Common::String verbString = getWord(line, index);
+
+ if (!_verbs.contains(verbString)) {
+ _display->printString(formatVerbError(verbString));
+ continue;
+ }
+
+ verb = _verbs[verbString];
+
+ Common::String nounString = getWord(line, index);
+
+ if (!_nouns.contains(nounString)) {
+ _display->printString(formatNounError(verbString, nounString));
+ continue;
+ }
+
+ noun = _nouns[nounString];
+ return;
+ }
+}
+
+bool AdlEngine::op_debug(const char *fmt, ...) const {
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript)) {
+ va_list va;
+ va_start(va, fmt);
+ Common::String output = Common::String::vformat(fmt, va);
+ va_end(va);
+
+ output += '\n';
+ if (_dumpFile) {
+ _dumpFile->write(output.c_str(), output.size());
+ return true;
+ } else
+ debugN("%s", output.c_str());
+ }
+
+ return false;
+}
+
+int AdlEngine::o1_isItemInRoom(ScriptEnv &e) {
+ OP_DEBUG_2("\t&& GET_ITEM_ROOM(%s) == %s", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ if (getItem(e.arg(1)).room == roomArg(e.arg(2)))
+ return 2;
+
+ return -1;
+}
+
+int AdlEngine::o1_isMovesGT(ScriptEnv &e) {
+ OP_DEBUG_1("\t&& MOVES > %d", e.arg(1));
+
+ if (_state.moves > e.arg(1))
+ return 1;
+
+ return -1;
+}
+
+int AdlEngine::o1_isVarEQ(ScriptEnv &e) {
+ OP_DEBUG_2("\t&& VARS[%d] == %d", e.arg(1), e.arg(2));
+
+ if (getVar(e.arg(1)) == e.arg(2))
+ return 2;
+
+ return -1;
+}
+
+int AdlEngine::o1_isCurPicEQ(ScriptEnv &e) {
+ OP_DEBUG_1("\t&& GET_CURPIC() == %d", e.arg(1));
+
+ if (getCurRoom().curPicture == e.arg(1))
+ return 1;
+
+ return -1;
+}
+
+int AdlEngine::o1_isItemPicEQ(ScriptEnv &e) {
+ OP_DEBUG_2("\t&& GET_ITEM_PIC(%s) == %d", itemStr(e.arg(1)).c_str(), e.arg(2));
+
+ if (getItem(e.arg(1)).picture == e.arg(2))
+ return 2;
+
+ return -1;
+}
+
+int AdlEngine::o1_varAdd(ScriptEnv &e) {
+ OP_DEBUG_2("\tVARS[%d] += %d", e.arg(2), e.arg(1));
+
+ setVar(e.arg(2), getVar(e.arg(2) + e.arg(1)));
+ return 2;
+}
+
+int AdlEngine::o1_varSub(ScriptEnv &e) {
+ OP_DEBUG_2("\tVARS[%d] -= %d", e.arg(2), e.arg(1));
+
+ setVar(e.arg(2), getVar(e.arg(2)) - e.arg(1));
+ return 2;
+}
+
+int AdlEngine::o1_varSet(ScriptEnv &e) {
+ OP_DEBUG_2("\tVARS[%d] = %d", e.arg(1), e.arg(2));
+
+ setVar(e.arg(1), e.arg(2));
+ return 2;
+}
+
+int AdlEngine::o1_listInv(ScriptEnv &e) {
+ OP_DEBUG_0("\tLIST_INVENTORY()");
+
+ Common::List<Item>::const_iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->room == IDI_ANY)
+ printMessage(item->description);
+
+ return 0;
+}
+
+int AdlEngine::o1_moveItem(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ getItem(e.arg(1)).room = e.arg(2);
+ return 2;
+}
+
+int AdlEngine::o1_setRoom(ScriptEnv &e) {
+ OP_DEBUG_1("\tROOM = %d", e.arg(1));
+
+ getCurRoom().curPicture = getCurRoom().picture;
+ _state.room = e.arg(1);
+ return 1;
+}
+
+int AdlEngine::o1_setCurPic(ScriptEnv &e) {
+ OP_DEBUG_1("\tSET_CURPIC(%d)", e.arg(1));
+
+ getCurRoom().curPicture = e.arg(1);
+ return 1;
+}
+
+int AdlEngine::o1_setPic(ScriptEnv &e) {
+ OP_DEBUG_1("\tSET_PIC(%d)", e.arg(1));
+
+ getCurRoom().picture = getCurRoom().curPicture = e.arg(1);
+ return 1;
+}
+
+int AdlEngine::o1_printMsg(ScriptEnv &e) {
+ OP_DEBUG_1("\tPRINT(%s)", msgStr(e.arg(1)).c_str());
+
+ printMessage(e.arg(1));
+ return 1;
+}
+
+int AdlEngine::o1_setLight(ScriptEnv &e) {
+ OP_DEBUG_0("\tLIGHT()");
+
+ _state.isDark = false;
+ return 0;
+}
+
+int AdlEngine::o1_setDark(ScriptEnv &e) {
+ OP_DEBUG_0("\tDARK()");
+
+ _state.isDark = true;
+ return 0;
+}
+
+int AdlEngine::o1_save(ScriptEnv &e) {
+ OP_DEBUG_0("\tSAVE_GAME()");
+
+ saveGameState(0, "");
+ return 0;
+}
+
+int AdlEngine::o1_restore(ScriptEnv &e) {
+ OP_DEBUG_0("\tRESTORE_GAME()");
+
+ loadGameState(0);
+ _isRestoring = false;
+ return 0;
+}
+
+int AdlEngine::o1_restart(ScriptEnv &e) {
+ OP_DEBUG_0("\tRESTART_GAME()");
+
+ _display->printString(_strings.playAgain);
+ Common::String input = inputString();
+
+ if (input.size() == 0 || input[0] != APPLECHAR('N')) {
+ _isRestarting = true;
+ _display->clear(0x00);
+ _display->updateHiResScreen();
+ _display->printString(_strings.pressReturn);
+ initState();
+ _display->printAsciiString(_strings.lineFeeds);
+ return -1;
+ }
+
+ return o1_quit(e);
+}
+
+int AdlEngine::o1_quit(ScriptEnv &e) {
+ OP_DEBUG_0("\tQUIT_GAME()");
+
+ printMessage(_messageIds.thanksForPlaying);
+ quitGame();
+ return -1;
+}
+
+int AdlEngine::o1_placeItem(ScriptEnv &e) {
+ OP_DEBUG_4("\tPLACE_ITEM(%s, %s, (%d, %d))", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str(), e.arg(3), e.arg(4));
+
+ Item &item = getItem(e.arg(1));
+
+ item.room = roomArg(e.arg(2));
+ item.position.x = e.arg(3);
+ item.position.y = e.arg(4);
+ return 4;
+}
+
+int AdlEngine::o1_setItemPic(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_ITEM_PIC(%s, %d)", itemStr(e.arg(2)).c_str(), e.arg(1));
+
+ getItem(e.arg(2)).picture = e.arg(1);
+ return 2;
+}
+
+int AdlEngine::o1_resetPic(ScriptEnv &e) {
+ OP_DEBUG_0("\tRESET_PIC()");
+
+ getCurRoom().curPicture = getCurRoom().picture;
+ return 0;
+}
+
+template <Direction D>
+int AdlEngine::o1_goDirection(ScriptEnv &e) {
+ OP_DEBUG_0((Common::String("\tGO_") + dirStr(D) + "()").c_str());
+
+ byte room = getCurRoom().connections[D];
+
+ if (room == 0) {
+ printMessage(_messageIds.cantGoThere);
+ return -1;
+ }
+
+ getCurRoom().curPicture = getCurRoom().picture;
+ _state.room = room;
+ return -1;
+}
+
+int AdlEngine::o1_takeItem(ScriptEnv &e) {
+ OP_DEBUG_0("\tTAKE_ITEM()");
+
+ takeItem(e.getNoun());
+ return 0;
+}
+
+int AdlEngine::o1_dropItem(ScriptEnv &e) {
+ OP_DEBUG_0("\tDROP_ITEM()");
+
+ dropItem(e.getNoun());
+ return 0;
+}
+
+int AdlEngine::o1_setRoomPic(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_ROOM_PIC(%d, %d)", e.arg(1), e.arg(2));
+
+ getRoom(e.arg(1)).picture = getRoom(e.arg(1)).curPicture = e.arg(2);
+ return 2;
+}
+
+bool AdlEngine::matchCommand(ScriptEnv &env) const {
+ if (!env.isMatch() && !_dumpFile)
+ return false;
+
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript)) {
+ op_debug("IF\n\tROOM == %s", roomStr(env.getCommand().room).c_str());
+ op_debug("\t&& SAID(%s, %s)", verbStr(env.getCommand().verb).c_str(), nounStr(env.getCommand().noun).c_str());
+ }
+
+ for (uint i = 0; i < env.getCondCount(); ++i) {
+ byte op = env.op();
+
+ if (op >= _condOpcodes.size() || !_condOpcodes[op] || !_condOpcodes[op]->isValid())
+ error("Unimplemented condition opcode %02x", op);
+
+ int numArgs = (*_condOpcodes[op])(env);
+
+ if (numArgs < 0) {
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript))
+ op_debug("FAIL\n");
+ return false;
+ }
+
+ env.skip(numArgs + 1);
+ }
+
+ return true;
+}
+
+void AdlEngine::doActions(ScriptEnv &env) {
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript))
+ op_debug("THEN");
+
+ for (uint i = 0; i < env.getActCount(); ++i) {
+ byte op = env.op();
+
+ if (op >= _actOpcodes.size() || !_actOpcodes[op] || !_actOpcodes[op]->isValid())
+ error("Unimplemented action opcode %02x", op);
+
+ int numArgs = (*_actOpcodes[op])(env);
+
+ if (numArgs < 0) {
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript))
+ op_debug("ABORT\n");
+ return;
+ }
+
+ env.skip(numArgs + 1);
+ }
+
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript))
+ op_debug("END\n");
+}
+
+bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) {
+ Commands::const_iterator cmd;
+
+ for (cmd = commands.begin(); cmd != commands.end(); ++cmd) {
+
+ if (_skipOneCommand) {
+ _skipOneCommand = false;
+ continue;
+ }
+
+ ScriptEnv env(*cmd, _state.room, verb, noun);
+ if (matchCommand(env)) {
+ doActions(env);
+ return true;
+ }
+ }
+
+ _skipOneCommand = false;
+ return false;
+}
+
+void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) {
+ Commands::const_iterator cmd;
+
+ for (cmd = commands.begin(); cmd != commands.end(); ++cmd) {
+ if (_skipOneCommand) {
+ _skipOneCommand = false;
+ continue;
+ }
+
+ ScriptEnv env(*cmd, _state.room, verb, noun);
+ if (matchCommand(env)) {
+ doActions(env);
+ // The original long jumps on restart, so we need to abort here
+ if (_isRestarting)
+ return;
+ }
+ }
+
+ _skipOneCommand = false;
+}
+
+Common::String AdlEngine::toAscii(const Common::String &str) {
+ Common::String ascii = Console::toAscii(str);
+ if (ascii.lastChar() == '\r')
+ ascii.deleteLastChar();
+ // FIXME: remove '\r's inside string?
+ return ascii;
+}
+
+Common::String AdlEngine::itemStr(uint i) const {
+ byte desc = getItem(i).description;
+ byte noun = getItem(i).noun;
+ Common::String name = Common::String::format("%d", i);
+ if (noun > 0) {
+ name += "/";
+ name += _priNouns[noun - 1];
+ }
+ if (desc > 0) {
+ name += "/";
+ name += toAscii(loadMessage(desc));
+ }
+ return name;
+}
+
+Common::String AdlEngine::itemRoomStr(uint i) const {
+ switch (i) {
+ case IDI_ANY:
+ return "CARRYING";
+ case IDI_VOID_ROOM:
+ return "GONE";
+ case IDI_CUR_ROOM:
+ return "HERE";
+ default:
+ return Common::String::format("%d", i);
+ }
+}
+
+Common::String AdlEngine::roomStr(uint i) const {
+ if (i == IDI_ANY)
+ return "*";
+ else
+ return Common::String::format("%d", i);
+}
+
+Common::String AdlEngine::verbStr(uint i) const {
+ if (i == IDI_ANY)
+ return "*";
+ else
+ return Common::String::format("%d/%s", i, _priVerbs[i - 1].c_str());
+}
+
+Common::String AdlEngine::nounStr(uint i) const {
+ if (i == IDI_ANY)
+ return "*";
+ else
+ return Common::String::format("%d/%s", i, _priNouns[i - 1].c_str());
+}
+
+Common::String AdlEngine::msgStr(uint i) const {
+ return Common::String::format("%d/%s", i, toAscii(loadMessage(i)).c_str());
+}
+
+Common::String AdlEngine::dirStr(Direction dir) const {
+ static const char *dirs[] = { "NORTH", "SOUTH", "EAST", "WEST", "UP", "DOWN" };
+ return dirs[dir];
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
new file mode 100644
index 0000000000..c9d77fcc62
--- /dev/null
+++ b/engines/adl/adl.h
@@ -0,0 +1,393 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_ADL_H
+#define ADL_ADL_H
+
+#include "common/debug-channels.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/str.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+#include "common/func.h"
+#include "common/scummsys.h"
+
+#include "engines/engine.h"
+
+#include "audio/mixer.h"
+#include "audio/softsynth/pcspk.h"
+
+#include "adl/console.h"
+#include "adl/disk.h"
+
+namespace Common {
+class ReadStream;
+class SeekableReadStream;
+class File;
+struct Event;
+}
+
+namespace Adl {
+
+class Console;
+class Display;
+class GraphicsMan;
+class Speaker;
+struct AdlGameDescription;
+class ScriptEnv;
+
+enum kDebugChannels {
+ kDebugChannelScript = 1 << 0
+};
+
+// Save and restore opcodes
+#define IDO_ACT_SAVE 0x0f
+#define IDO_ACT_LOAD 0x10
+
+#define IDI_CUR_ROOM 0xfc
+#define IDI_VOID_ROOM 0xfd
+#define IDI_ANY 0xfe
+
+#define IDI_WORD_SIZE 8
+
+enum Direction {
+ IDI_DIR_NORTH,
+ IDI_DIR_SOUTH,
+ IDI_DIR_EAST,
+ IDI_DIR_WEST,
+ IDI_DIR_UP,
+ IDI_DIR_DOWN,
+ IDI_DIR_TOTAL
+};
+
+struct Room {
+ Room() :
+ description(0),
+ picture(0),
+ curPicture(0) {
+ memset(connections, 0, sizeof(connections));
+ }
+
+ byte description;
+ byte connections[IDI_DIR_TOTAL];
+ DataBlockPtr data;
+ byte picture;
+ byte curPicture;
+ bool isFirstTime;
+};
+
+typedef Common::HashMap<byte, DataBlockPtr> PictureMap;
+
+typedef Common::Array<byte> Script;
+
+struct Command {
+ byte room;
+ byte verb, noun;
+ byte numCond, numAct;
+ Script script;
+};
+
+class ScriptEnv {
+public:
+ ScriptEnv(const Command &cmd, byte room, byte verb, byte noun) :
+ _cmd(cmd), _room(room), _verb(verb), _noun(noun), _ip(0) { }
+
+ byte op() const { return _cmd.script[_ip]; }
+ // We keep this 1-based for easier comparison with the original engine
+ byte arg(uint i) const { return _cmd.script[_ip + i]; }
+ void skip(uint i) { _ip += i; }
+
+ bool isMatch() const {
+ return (_cmd.room == IDI_ANY || _cmd.room == _room) &&
+ (_cmd.verb == IDI_ANY || _cmd.verb == _verb) &&
+ (_cmd.noun == IDI_ANY || _cmd.noun == _noun);
+ }
+
+ byte getCondCount() const { return _cmd.numCond; }
+ byte getActCount() const { return _cmd.numAct; }
+ byte getNoun() const { return _noun; }
+ const Command &getCommand() const { return _cmd; }
+
+private:
+ const Command &_cmd;
+ const byte _room, _verb, _noun;
+ byte _ip;
+};
+
+enum {
+ IDI_ITEM_NOT_MOVED,
+ IDI_ITEM_DROPPED,
+ IDI_ITEM_DOESNT_MOVE
+};
+
+struct Item {
+ byte id;
+ byte noun;
+ byte room;
+ byte picture;
+ bool isLineArt;
+ Common::Point position;
+ int state;
+ byte description;
+ Common::Array<byte> roomPictures;
+ bool isOnScreen;
+};
+
+struct Time {
+ byte hours, minutes;
+
+ Time() : hours(12), minutes(0) { }
+};
+
+struct State {
+ Common::Array<Room> rooms;
+ Common::List<Item> items;
+ Common::Array<byte> vars;
+
+ byte room;
+ uint16 moves;
+ bool isDark;
+ Time time;
+
+ State() : room(1), moves(1), isDark(false) { }
+};
+
+typedef Common::List<Command> Commands;
+typedef Common::HashMap<Common::String, uint> WordMap;
+
+struct RoomData {
+ Common::String description;
+ PictureMap pictures;
+ Commands commands;
+};
+
+// Opcode debugging macros
+#define OP_DEBUG_0(F) do { \
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F)) \
+ return 0; \
+} while (0)
+
+#define OP_DEBUG_1(F, P1) do { \
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1)) \
+ return 1; \
+} while (0)
+
+#define OP_DEBUG_2(F, P1, P2) do { \
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1, P2)) \
+ return 2; \
+} while (0)
+
+#define OP_DEBUG_3(F, P1, P2, P3) do { \
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1, P2, P3)) \
+ return 3; \
+} while (0)
+
+#define OP_DEBUG_4(F, P1, P2, P3, P4) do { \
+ if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1, P2, P3, P4)) \
+ return 4; \
+} while (0)
+
+class AdlEngine : public Engine {
+friend class Console;
+public:
+ virtual ~AdlEngine();
+
+ bool pollEvent(Common::Event &event) const;
+
+protected:
+ AdlEngine(OSystem *syst, const AdlGameDescription *gd);
+
+ // Engine
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameState(int slot, const Common::String &desc);
+
+ Common::String readString(Common::ReadStream &stream, byte until = 0) const;
+ Common::String readStringAt(Common::SeekableReadStream &stream, uint offset, byte until = 0) const;
+ void openFile(Common::File &file, const Common::String &name) const;
+
+ virtual void printString(const Common::String &str) = 0;
+ virtual Common::String loadMessage(uint idx) const = 0;
+ virtual void printMessage(uint idx);
+ virtual Common::String getItemDescription(const Item &item) const;
+ void delay(uint32 ms) const;
+
+ Common::String inputString(byte prompt = 0) const;
+ byte inputKey(bool showCursor = true) const;
+
+ virtual Common::String formatVerbError(const Common::String &verb) const;
+ virtual Common::String formatNounError(const Common::String &verb, const Common::String &noun) const;
+ void loadWords(Common::ReadStream &stream, WordMap &map, Common::StringArray &pri) const;
+ void readCommands(Common::ReadStream &stream, Commands &commands);
+ void checkInput(byte verb, byte noun);
+ virtual bool isInputValid(byte verb, byte noun, bool &is_any);
+ virtual bool isInputValid(const Commands &commands, byte verb, byte noun, bool &is_any);
+
+ virtual void setupOpcodeTables();
+ virtual void initState();
+ virtual byte roomArg(byte room) const;
+ virtual void advanceClock() { }
+
+ // Opcodes
+ int o1_isItemInRoom(ScriptEnv &e);
+ int o1_isMovesGT(ScriptEnv &e);
+ int o1_isVarEQ(ScriptEnv &e);
+ int o1_isCurPicEQ(ScriptEnv &e);
+ int o1_isItemPicEQ(ScriptEnv &e);
+
+ int o1_varAdd(ScriptEnv &e);
+ int o1_varSub(ScriptEnv &e);
+ int o1_varSet(ScriptEnv &e);
+ int o1_listInv(ScriptEnv &e);
+ int o1_moveItem(ScriptEnv &e);
+ int o1_setRoom(ScriptEnv &e);
+ int o1_setCurPic(ScriptEnv &e);
+ int o1_setPic(ScriptEnv &e);
+ int o1_printMsg(ScriptEnv &e);
+ int o1_setLight(ScriptEnv &e);
+ int o1_setDark(ScriptEnv &e);
+ int o1_save(ScriptEnv &e);
+ int o1_restore(ScriptEnv &e);
+ int o1_restart(ScriptEnv &e);
+ int o1_quit(ScriptEnv &e);
+ int o1_placeItem(ScriptEnv &e);
+ int o1_setItemPic(ScriptEnv &e);
+ int o1_resetPic(ScriptEnv &e);
+ template <Direction D>
+ int o1_goDirection(ScriptEnv &e);
+ int o1_takeItem(ScriptEnv &e);
+ int o1_dropItem(ScriptEnv &e);
+ int o1_setRoomPic(ScriptEnv &e);
+
+ // Graphics
+ void clearScreen() const;
+ void drawPic(byte pic, Common::Point pos = Common::Point()) const;
+
+ // Sound
+ void bell(uint count = 1) const;
+
+ // Game state functions
+ const Room &getRoom(uint i) const;
+ Room &getRoom(uint i);
+ const Room &getCurRoom() const;
+ Room &getCurRoom();
+ const Item &getItem(uint i) const;
+ Item &getItem(uint i);
+ byte getVar(uint i) const;
+ void setVar(uint i, byte value);
+ virtual void takeItem(byte noun);
+ void dropItem(byte noun);
+ bool matchCommand(ScriptEnv &env) const;
+ void doActions(ScriptEnv &env);
+ bool doOneCommand(const Commands &commands, byte verb, byte noun);
+ void doAllCommands(const Commands &commands, byte verb, byte noun);
+
+ // Debug functions
+ static Common::String toAscii(const Common::String &str);
+ Common::String itemStr(uint i) const;
+ Common::String roomStr(uint i) const;
+ Common::String itemRoomStr(uint i) const;
+ Common::String verbStr(uint i) const;
+ Common::String nounStr(uint i) const;
+ Common::String msgStr(uint i) const;
+ Common::String dirStr(Direction dir) const;
+ bool op_debug(const char *fmt, ...) const;
+ Common::DumpFile *_dumpFile;
+
+ Display *_display;
+ GraphicsMan *_graphics;
+ Speaker *_speaker;
+
+ // Opcodes
+ typedef Common::Functor1<ScriptEnv &, int> Opcode;
+ Common::Array<const Opcode *> _condOpcodes, _actOpcodes;
+ // Message strings in data file
+ Common::Array<DataBlockPtr> _messages;
+ // Picture data
+ PictureMap _pictures;
+ // Dropped item screen offsets
+ Common::Array<Common::Point> _itemOffsets;
+ // <room, verb, noun, script> lists
+ Commands _roomCommands;
+ Commands _globalCommands;
+ // Data related to the current room
+ RoomData _roomData;
+
+ WordMap _verbs;
+ WordMap _nouns;
+ Common::StringArray _priVerbs;
+ Common::StringArray _priNouns;
+
+ struct {
+ Common::String enterCommand;
+ Common::String verbError;
+ Common::String nounError;
+ Common::String playAgain;
+ Common::String pressReturn;
+ Common::String lineFeeds;
+ } _strings;
+
+ struct {
+ uint cantGoThere;
+ uint dontUnderstand;
+ uint itemDoesntMove;
+ uint itemNotHere;
+ uint thanksForPlaying;
+ } _messageIds;
+
+ // Game state
+ State _state;
+
+ bool _isRestarting, _isRestoring;
+ bool _skipOneCommand;
+
+private:
+ virtual void runIntro() const { }
+ virtual void init() = 0;
+ virtual void initGameState() = 0;
+ virtual void drawItems() = 0;
+ virtual void drawItem(Item &item, const Common::Point &pos) = 0;
+ virtual void loadRoom(byte roomNr) = 0;
+ virtual void showRoom() = 0;
+
+ // Engine
+ Common::Error run();
+ bool hasFeature(EngineFeature f) const;
+ bool canLoadGameStateCurrently();
+ bool canSaveGameStateCurrently();
+
+ // Text input
+ byte convertKey(uint16 ascii) const;
+ Common::String getLine() const;
+ Common::String getWord(const Common::String &line, uint &index) const;
+ void getInput(uint &verb, uint &noun);
+
+ Console *_console;
+ GUI::Debugger *getDebugger() { return _console; }
+ const AdlGameDescription *_gameDescription;
+ byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun;
+ bool _canSaveNow, _canRestoreNow;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp
new file mode 100644
index 0000000000..4fdf796701
--- /dev/null
+++ b/engines/adl/adl_v2.cpp
@@ -0,0 +1,539 @@
+/* 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.
+ *
+ */
+
+#include "common/random.h"
+#include "common/error.h"
+
+#include "adl/adl_v2.h"
+#include "adl/display.h"
+#include "adl/graphics.h"
+
+namespace Adl {
+
+AdlEngine_v2::~AdlEngine_v2() {
+ delete _random;
+ delete _disk;
+}
+
+AdlEngine_v2::AdlEngine_v2(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine(syst, gd),
+ _linesPrinted(0),
+ _disk(nullptr),
+ _itemRemoved(false),
+ _roomOnScreen(0),
+ _picOnScreen(0),
+ _itemsOnScreen(0) {
+ _random = new Common::RandomSource("adl");
+}
+
+typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine_v2> OpcodeV2;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV2(this, &AdlEngine_v2::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV2(this, 0))
+
+void AdlEngine_v2::setupOpcodeTables() {
+ Common::Array<const Opcode *> *table = 0;
+
+ SetOpcodeTable(_condOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o2_isFirstTime);
+ Opcode(o2_isRandomGT);
+ Opcode(o1_isItemInRoom);
+ // 0x04
+ Opcode(o2_isNounNotInRoom);
+ Opcode(o1_isMovesGT);
+ Opcode(o1_isVarEQ);
+ Opcode(o2_isCarryingSomething);
+ // 0x08
+ OpcodeUnImpl();
+ Opcode(o1_isCurPicEQ);
+ Opcode(o1_isItemPicEQ);
+
+ SetOpcodeTable(_actOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o1_varAdd);
+ Opcode(o1_varSub);
+ Opcode(o1_varSet);
+ // 0x04
+ Opcode(o1_listInv);
+ Opcode(o2_moveItem);
+ Opcode(o1_setRoom);
+ Opcode(o1_setCurPic);
+ // 0x08
+ Opcode(o1_setPic);
+ Opcode(o1_printMsg);
+ Opcode(o1_setLight);
+ Opcode(o1_setDark);
+ // 0x0c
+ Opcode(o2_moveAllItems);
+ Opcode(o1_quit);
+ OpcodeUnImpl();
+ Opcode(o2_save);
+ // 0x10
+ Opcode(o2_restore);
+ Opcode(o1_restart);
+ Opcode(o2_placeItem);
+ Opcode(o1_setItemPic);
+ // 0x14
+ Opcode(o1_resetPic);
+ Opcode(o1_goDirection<IDI_DIR_NORTH>);
+ Opcode(o1_goDirection<IDI_DIR_SOUTH>);
+ Opcode(o1_goDirection<IDI_DIR_EAST>);
+ // 0x18
+ Opcode(o1_goDirection<IDI_DIR_WEST>);
+ Opcode(o1_goDirection<IDI_DIR_UP>);
+ Opcode(o1_goDirection<IDI_DIR_DOWN>);
+ Opcode(o1_takeItem);
+ // 0x1c
+ Opcode(o1_dropItem);
+ Opcode(o1_setRoomPic);
+ Opcode(o2_tellTime);
+ Opcode(o2_setRoomFromVar);
+ // 0x20
+ Opcode(o2_initDisk);
+}
+
+void AdlEngine_v2::initState() {
+ AdlEngine::initState();
+
+ _linesPrinted = 0;
+ _picOnScreen = 0;
+ _roomOnScreen = 0;
+ _itemRemoved = false;
+ _itemsOnScreen = 0;
+}
+
+byte AdlEngine_v2::roomArg(byte room) const {
+ if (room == IDI_CUR_ROOM)
+ return _state.room;
+ return room;
+}
+
+void AdlEngine_v2::advanceClock() {
+ Time &time = _state.time;
+
+ time.minutes += 5;
+
+ if (time.minutes == 60) {
+ time.minutes = 0;
+
+ ++time.hours;
+
+ if (time.hours == 13)
+ time.hours = 1;
+ }
+}
+
+void AdlEngine_v2::checkTextOverflow(char c) {
+ if (c != APPLECHAR('\r'))
+ return;
+
+ ++_linesPrinted;
+
+ if (_linesPrinted < 4)
+ return;
+
+ _linesPrinted = 0;
+ _display->updateTextScreen();
+ bell();
+
+ while (true) {
+ char key = inputKey(false);
+
+ if (shouldQuit())
+ return;
+
+ if (key == APPLECHAR('\r'))
+ break;
+
+ bell(3);
+ }
+}
+
+Common::String AdlEngine_v2::loadMessage(uint idx) const {
+ if (_messages[idx]) {
+ StreamPtr strStream(_messages[idx]->createReadStream());
+ return readString(*strStream, 0xff);
+ }
+
+ return Common::String();
+}
+
+void AdlEngine_v2::printString(const Common::String &str) {
+ Common::String s(str);
+ byte endPos = TEXT_WIDTH - 1;
+ byte pos = 0;
+
+ while (true) {
+ while (pos <= endPos && pos != s.size()) {
+ s.setChar(APPLECHAR(s[pos]), pos);
+ ++pos;
+ }
+
+ if (pos == s.size())
+ break;
+
+ while (s[pos] != APPLECHAR(' ') && s[pos] != APPLECHAR('\r'))
+ --pos;
+
+ s.setChar(APPLECHAR('\r'), pos);
+ endPos = pos + TEXT_WIDTH;
+ ++pos;
+ }
+
+ pos = 0;
+ while (pos != s.size()) {
+ checkTextOverflow(s[pos]);
+ _display->printChar(s[pos]);
+ ++pos;
+ }
+
+ checkTextOverflow(APPLECHAR('\r'));
+ _display->printChar(APPLECHAR('\r'));
+ _display->updateTextScreen();
+}
+
+void AdlEngine_v2::drawItem(Item &item, const Common::Point &pos) {
+ item.isOnScreen = true;
+ StreamPtr stream(_itemPics[item.picture - 1]->createReadStream());
+ stream->readByte(); // Skip clear opcode
+ _graphics->drawPic(*stream, pos);
+}
+
+void AdlEngine_v2::loadRoom(byte roomNr) {
+ Room &room = getRoom(roomNr);
+ StreamPtr stream(room.data->createReadStream());
+
+ uint16 descOffset = stream->readUint16LE();
+ uint16 commandOffset = stream->readUint16LE();
+
+ _roomData.pictures.clear();
+ // There's no picture count. The original engine always checks at most
+ // five pictures. We use the description offset to bound our search.
+ uint16 picCount = (descOffset - 4) / 5;
+
+ for (uint i = 0; i < picCount; ++i) {
+ byte nr = stream->readByte();
+ _roomData.pictures[nr] = readDataBlockPtr(*stream);
+ }
+
+ _roomData.description = readStringAt(*stream, descOffset, 0xff);
+
+ _roomData.commands.clear();
+ if (commandOffset != 0) {
+ stream->seek(commandOffset);
+ readCommands(*stream, _roomData.commands);
+ }
+}
+
+void AdlEngine_v2::showRoom() {
+ bool redrawPic = false;
+
+ if (_state.room != _roomOnScreen) {
+ loadRoom(_state.room);
+ clearScreen();
+
+ if (!_state.isDark)
+ redrawPic = true;
+ } else {
+ if (getCurRoom().curPicture != _picOnScreen || _itemRemoved)
+ redrawPic = true;
+ }
+
+ if (redrawPic) {
+ _roomOnScreen = _state.room;
+ _picOnScreen = getCurRoom().curPicture;
+
+ drawPic(getCurRoom().curPicture);
+ _itemRemoved = false;
+ _itemsOnScreen = 0;
+
+ Common::List<Item>::iterator item;
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ item->isOnScreen = false;
+ }
+
+ if (!_state.isDark)
+ drawItems();
+
+ _display->updateHiResScreen();
+ printString(_roomData.description);
+
+ // FIXME: move to main loop?
+ _linesPrinted = 0;
+}
+
+void AdlEngine_v2::takeItem(byte noun) {
+ Common::List<Item>::iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ if (item->noun != noun || item->room != _state.room)
+ continue;
+
+ if (item->state == IDI_ITEM_DOESNT_MOVE) {
+ printMessage(_messageIds.itemDoesntMove);
+ return;
+ }
+
+ if (item->state == IDI_ITEM_DROPPED) {
+ item->room = IDI_ANY;
+ _itemRemoved = true;
+ return;
+ }
+
+ Common::Array<byte>::const_iterator pic;
+ for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) {
+ if (*pic == getCurRoom().curPicture || *pic == IDI_ANY) {
+ item->room = IDI_ANY;
+ _itemRemoved = true;
+ item->state = IDI_ITEM_DROPPED;
+ return;
+ }
+ }
+ }
+
+ printMessage(_messageIds.itemNotHere);
+}
+
+void AdlEngine_v2::drawItems() {
+ Common::List<Item>::iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ // Skip items not in this room
+ if (item->room != _state.room)
+ continue;
+
+ if (item->isOnScreen)
+ continue;
+
+ if (item->state == IDI_ITEM_DROPPED) {
+ // Draw dropped item if in normal view
+ if (getCurRoom().picture == getCurRoom().curPicture)
+ drawItem(*item, _itemOffsets[_itemsOnScreen++]);
+ } else {
+ // Draw fixed item if current view is in the pic list
+ Common::Array<byte>::const_iterator pic;
+
+ for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) {
+ if (*pic == getCurRoom().curPicture || *pic == IDI_ANY) {
+ drawItem(*item, item->position);
+ break;
+ }
+ }
+ }
+ }
+}
+
+DataBlockPtr AdlEngine_v2::readDataBlockPtr(Common::ReadStream &f) const {
+ byte track = f.readByte();
+ byte sector = f.readByte();
+ byte offset = f.readByte();
+ byte size = f.readByte();
+
+ if (f.eos() || f.err())
+ error("Error reading DataBlockPtr");
+
+ if (track == 0 && sector == 0 && offset == 0 && size == 0)
+ return DataBlockPtr();
+
+ return _disk->getDataBlock(track, sector, offset, size);
+}
+
+int AdlEngine_v2::o2_isFirstTime(ScriptEnv &e) {
+ OP_DEBUG_0("\t&& IS_FIRST_TIME()");
+
+ bool oldFlag = getCurRoom().isFirstTime;
+
+ getCurRoom().isFirstTime = false;
+
+ if (!oldFlag)
+ return -1;
+
+ return 0;
+}
+
+int AdlEngine_v2::o2_isRandomGT(ScriptEnv &e) {
+ OP_DEBUG_1("\t&& RAND() > %d", e.arg(1));
+
+ byte rnd = _random->getRandomNumber(255);
+
+ if (rnd > e.arg(1))
+ return 1;
+
+ return -1;
+}
+
+int AdlEngine_v2::o2_isNounNotInRoom(ScriptEnv &e) {
+ OP_DEBUG_1("\t&& NO_SUCH_ITEMS_IN_ROOM(%s)", itemRoomStr(e.arg(1)).c_str());
+
+ Common::List<Item>::const_iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->noun == e.getNoun() && (item->room == roomArg(e.arg(1))))
+ return -1;
+
+ return 1;
+}
+
+int AdlEngine_v2::o2_isCarryingSomething(ScriptEnv &e) {
+ OP_DEBUG_0("\t&& IS_CARRYING_SOMETHING()");
+
+ Common::List<Item>::const_iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->room == IDI_ANY)
+ return 0;
+ return -1;
+}
+
+int AdlEngine_v2::o2_moveItem(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ byte room = roomArg(e.arg(2));
+
+ Item &item = getItem(e.arg(1));
+
+ if (item.room == _roomOnScreen)
+ _picOnScreen = 0;
+
+ // Set items that move from inventory to a room to state "dropped"
+ if (item.room == IDI_ANY && room != IDI_VOID_ROOM)
+ item.state = IDI_ITEM_DROPPED;
+
+ item.room = room;
+ return 2;
+}
+
+int AdlEngine_v2::o2_moveAllItems(ScriptEnv &e) {
+ OP_DEBUG_2("\tMOVE_ALL_ITEMS(%s, %s)", itemRoomStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ byte room1 = roomArg(e.arg(1));
+
+ if (room1 == _state.room)
+ _picOnScreen = 0;
+
+ byte room2 = roomArg(e.arg(2));
+
+ Common::List<Item>::iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->room == room1) {
+ item->room = room2;
+ if (room1 == IDI_ANY)
+ item->state = IDI_ITEM_DROPPED;
+ }
+
+ return 2;
+}
+
+int AdlEngine_v2::o2_save(ScriptEnv &e) {
+ OP_DEBUG_0("\tSAVE_GAME()");
+
+ int slot = askForSlot(_strings_v2.saveInsert);
+
+ if (slot < 0)
+ return -1;
+
+ saveGameState(slot, "");
+
+ _display->printString(_strings_v2.saveReplace);
+ inputString();
+ return 0;
+}
+
+int AdlEngine_v2::o2_restore(ScriptEnv &e) {
+ OP_DEBUG_0("\tRESTORE_GAME()");
+
+ int slot = askForSlot(_strings_v2.restoreInsert);
+
+ if (slot < 0)
+ return -1;
+
+ loadGameState(slot);
+ _isRestoring = false;
+
+ _display->printString(_strings_v2.restoreReplace);
+ inputString();
+ _picOnScreen = 0;
+ _roomOnScreen = 0;
+ return 0;
+}
+
+int AdlEngine_v2::o2_placeItem(ScriptEnv &e) {
+ OP_DEBUG_4("\tPLACE_ITEM(%s, %s, (%d, %d))", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str(), e.arg(3), e.arg(4));
+
+ Item &item = getItem(e.arg(1));
+
+ item.room = roomArg(e.arg(2));
+ item.position.x = e.arg(3);
+ item.position.y = e.arg(4);
+ item.state = IDI_ITEM_NOT_MOVED;
+
+ return 4;
+}
+
+int AdlEngine_v2::o2_tellTime(ScriptEnv &e) {
+ OP_DEBUG_0("\tTELL_TIME()");
+
+ Common::String time = _strings_v2.time;
+
+ time.setChar(APPLECHAR('0') + _state.time.hours / 10, 12);
+ time.setChar(APPLECHAR('0') + _state.time.hours % 10, 13);
+ time.setChar(APPLECHAR('0') + _state.time.minutes / 10, 15);
+ time.setChar(APPLECHAR('0') + _state.time.minutes % 10, 16);
+
+ printString(time);
+
+ return 0;
+}
+
+int AdlEngine_v2::o2_setRoomFromVar(ScriptEnv &e) {
+ OP_DEBUG_1("\tROOM = VAR[%d]", e.arg(1));
+ getCurRoom().curPicture = getCurRoom().picture;
+ _state.room = getVar(e.arg(1));
+ return 1;
+}
+
+int AdlEngine_v2::o2_initDisk(ScriptEnv &e) {
+ OP_DEBUG_0("\tINIT_DISK()");
+
+ _display->printAsciiString("NOT REQUIRED\r");
+ return 0;
+}
+
+int AdlEngine_v2::askForSlot(const Common::String &question) {
+ while (1) {
+ _display->printString(question);
+
+ Common::String input = inputString();
+
+ if (shouldQuit())
+ return -1;
+
+ if (input.size() > 0 && input[0] >= APPLECHAR('A') && input[0] <= APPLECHAR('O'))
+ return input[0] - APPLECHAR('A');
+ }
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/adl_v2.h b/engines/adl/adl_v2.h
new file mode 100644
index 0000000000..f18972b74b
--- /dev/null
+++ b/engines/adl/adl_v2.h
@@ -0,0 +1,95 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_ADL_V2_H
+#define ADL_ADL_V2_H
+
+#include "adl/adl.h"
+
+// Note: this version of ADL redraws only when necessary, but
+// this is not currently implemented.
+
+namespace Common {
+class RandomSource;
+}
+
+namespace Adl {
+
+class AdlEngine_v2 : public AdlEngine {
+public:
+ virtual ~AdlEngine_v2();
+
+protected:
+ AdlEngine_v2(OSystem *syst, const AdlGameDescription *gd);
+
+ // AdlEngine
+ virtual void setupOpcodeTables();
+ virtual void initState();
+ byte roomArg(byte room) const;
+ void advanceClock();
+ virtual void printString(const Common::String &str);
+ virtual Common::String loadMessage(uint idx) const;
+ void drawItems();
+ void drawItem(Item &item, const Common::Point &pos);
+ void loadRoom(byte roomNr);
+ virtual void showRoom();
+ void takeItem(byte noun);
+
+ virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const;
+
+ void checkTextOverflow(char c);
+
+ int o2_isFirstTime(ScriptEnv &e);
+ int o2_isRandomGT(ScriptEnv &e);
+ int o2_isNounNotInRoom(ScriptEnv &e);
+ int o2_isCarryingSomething(ScriptEnv &e);
+
+ int o2_moveItem(ScriptEnv &e);
+ int o2_moveAllItems(ScriptEnv &e);
+ int o2_save(ScriptEnv &e);
+ int o2_restore(ScriptEnv &e);
+ int o2_placeItem(ScriptEnv &e);
+ int o2_tellTime(ScriptEnv &e);
+ int o2_setRoomFromVar(ScriptEnv &e);
+ int o2_initDisk(ScriptEnv &e);
+
+ struct {
+ Common::String time;
+ Common::String saveInsert, saveReplace;
+ Common::String restoreInsert, restoreReplace;
+ } _strings_v2;
+
+ uint _linesPrinted;
+ DiskImage *_disk;
+ Common::Array<DataBlockPtr> _itemPics;
+ bool _itemRemoved;
+ byte _roomOnScreen, _picOnScreen, _itemsOnScreen;
+
+private:
+ int askForSlot(const Common::String &question);
+
+ Common::RandomSource *_random;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/adl_v3.cpp b/engines/adl/adl_v3.cpp
new file mode 100644
index 0000000000..623db661bc
--- /dev/null
+++ b/engines/adl/adl_v3.cpp
@@ -0,0 +1,259 @@
+/* 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.
+ *
+ */
+
+#include "common/random.h"
+#include "common/error.h"
+
+#include "adl/adl_v3.h"
+#include "adl/display.h"
+#include "adl/graphics.h"
+
+namespace Adl {
+
+AdlEngine_v3::AdlEngine_v3(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v2(syst, gd),
+ _curDisk(0) {
+}
+
+Common::String AdlEngine_v3::loadMessage(uint idx) const {
+ Common::String str = AdlEngine_v2::loadMessage(idx);
+
+ for (uint i = 0; i < str.size(); ++i) {
+ const char *xorStr = "AVISDURGAN";
+ str.setChar(str[i] ^ xorStr[i % strlen(xorStr)], i);
+ }
+
+ return str;
+}
+
+Common::String AdlEngine_v3::getItemDescription(const Item &item) const {
+ return _itemDesc[item.id - 1];
+}
+
+void AdlEngine_v3::applyDiskOffset(byte &track, byte &sector) const {
+ sector += _diskOffsets[_curDisk].sector;
+ if (sector >= 16) {
+ sector -= 16;
+ ++track;
+ }
+
+ track += _diskOffsets[_curDisk].track;
+}
+
+DataBlockPtr AdlEngine_v3::readDataBlockPtr(Common::ReadStream &f) const {
+ byte track = f.readByte();
+ byte sector = f.readByte();
+ byte offset = f.readByte();
+ byte size = f.readByte();
+
+ if (f.eos() || f.err())
+ error("Error reading DataBlockPtr");
+
+ if (track == 0 && sector == 0 && offset == 0 && size == 0)
+ return DataBlockPtr();
+
+ applyDiskOffset(track, sector);
+
+ return _disk->getDataBlock(track, sector, offset, size);
+}
+
+typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine_v3> OpcodeV3;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV3(this, &AdlEngine_v3::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV3(this, 0))
+
+void AdlEngine_v3::setupOpcodeTables() {
+ Common::Array<const Opcode *> *table = 0;
+
+ SetOpcodeTable(_condOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o2_isFirstTime);
+ Opcode(o2_isRandomGT);
+ Opcode(o3_isItemInRoom);
+ // 0x04
+ Opcode(o3_isNounNotInRoom);
+ Opcode(o1_isMovesGT);
+ Opcode(o1_isVarEQ);
+ Opcode(o2_isCarryingSomething);
+ // 0x08
+ Opcode(o3_isVarGT);
+ Opcode(o1_isCurPicEQ);
+ Opcode(o3_skipOneCommand);
+
+ SetOpcodeTable(_actOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o1_varAdd);
+ Opcode(o1_varSub);
+ Opcode(o1_varSet);
+ // 0x04
+ Opcode(o1_listInv);
+ Opcode(o3_moveItem);
+ Opcode(o1_setRoom);
+ Opcode(o1_setCurPic);
+ // 0x08
+ Opcode(o1_setPic);
+ Opcode(o1_printMsg);
+ Opcode(o3_dummy);
+ Opcode(o3_setTextMode);
+ // 0x0c
+ Opcode(o2_moveAllItems);
+ Opcode(o1_quit);
+ Opcode(o3_dummy);
+ Opcode(o2_save);
+ // 0x10
+ Opcode(o2_restore);
+ Opcode(o1_restart);
+ Opcode(o3_setDisk);
+ Opcode(o3_dummy);
+ // 0x14
+ Opcode(o1_resetPic);
+ Opcode(o1_goDirection<IDI_DIR_NORTH>);
+ Opcode(o1_goDirection<IDI_DIR_SOUTH>);
+ Opcode(o1_goDirection<IDI_DIR_EAST>);
+ // 0x18
+ Opcode(o1_goDirection<IDI_DIR_WEST>);
+ Opcode(o1_goDirection<IDI_DIR_UP>);
+ Opcode(o1_goDirection<IDI_DIR_DOWN>);
+ Opcode(o1_takeItem);
+ // 0x1c
+ Opcode(o1_dropItem);
+ Opcode(o1_setRoomPic);
+ Opcode(o3_sound);
+ OpcodeUnImpl();
+ // 0x20
+ Opcode(o2_initDisk);
+}
+
+int AdlEngine_v3::o3_isVarGT(ScriptEnv &e) {
+ OP_DEBUG_2("\t&& VARS[%d] > %d", e.arg(1), e.arg(2));
+
+ if (getVar(e.arg(1)) > e.arg(2))
+ return 2;
+
+ return -1;
+}
+
+int AdlEngine_v3::o3_skipOneCommand(ScriptEnv &e) {
+ OP_DEBUG_0("\t&& SKIP_ONE_COMMAND()");
+
+ _skipOneCommand = true;
+ setVar(2, 0);
+
+ return -1;
+}
+
+// FIXME: Rename "isLineArt" and look at code duplication
+int AdlEngine_v3::o3_isItemInRoom(ScriptEnv &e) {
+ OP_DEBUG_2("\t&& GET_ITEM_ROOM(%s) == %s", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ const Item &item = getItem(e.arg(1));
+
+ if (e.arg(2) != IDI_ANY && item.isLineArt != _curDisk)
+ return -1;
+
+ if (item.room == roomArg(e.arg(2)))
+ return 2;
+
+ return -1;
+}
+
+int AdlEngine_v3::o3_isNounNotInRoom(ScriptEnv &e) {
+ OP_DEBUG_1("\t&& NO_SUCH_ITEMS_IN_ROOM(%s)", itemRoomStr(e.arg(1)).c_str());
+
+ Common::List<Item>::const_iterator item;
+
+ setVar(24, 0);
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->noun == e.getNoun()) {
+ setVar(24, 1);
+
+ if (item->room == roomArg(e.arg(1)))
+ return -1;
+ }
+
+ return 1;
+}
+
+int AdlEngine_v3::o3_moveItem(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ byte room = roomArg(e.arg(2));
+
+ Item &item = getItem(e.arg(1));
+
+ if (item.room == _roomOnScreen)
+ _picOnScreen = 0;
+
+ // Set items that move from inventory to a room to state "dropped"
+ if (item.room == IDI_ANY && room != IDI_VOID_ROOM)
+ item.state = IDI_ITEM_DROPPED;
+
+ item.room = room;
+ item.isLineArt = _curDisk;
+ return 2;
+}
+
+int AdlEngine_v3::o3_dummy(ScriptEnv &e) {
+ OP_DEBUG_0("\tDUMMY()");
+
+ return 0;
+}
+
+int AdlEngine_v3::o3_setTextMode(ScriptEnv &e) {
+ OP_DEBUG_1("\tSET_TEXT_MODE(%d)", e.arg(1));
+
+ // TODO
+ // 1: 4-line mode
+ // 2: 24-line mode
+
+ switch (e.arg(1)) {
+ case 3:
+ // We re-use the restarting flag here, to simulate a long jump
+ _isRestarting = true;
+ return -1;
+ }
+
+ return 1;
+}
+
+int AdlEngine_v3::o3_setDisk(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_DISK(%d, %d)", e.arg(1), e.arg(2));
+
+ // TODO
+ // Arg 1: disk
+ // Arg 2: room
+
+ return 2;
+}
+
+int AdlEngine_v3::o3_sound(ScriptEnv &e) {
+ OP_DEBUG_0("\tSOUND()");
+
+ // TODO
+
+ return 0;
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/adl_v3.h b/engines/adl/adl_v3.h
new file mode 100644
index 0000000000..61dd5852e7
--- /dev/null
+++ b/engines/adl/adl_v3.h
@@ -0,0 +1,76 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_ADL_V3_H
+#define ADL_ADL_V3_H
+
+#include "adl/adl_v2.h"
+
+// Note: this version of ADL redraws only when necessary, but
+// this is not currently implemented.
+
+namespace Common {
+class RandomSource;
+}
+
+struct DiskOffset {
+ byte track;
+ byte sector;
+};
+
+namespace Adl {
+
+class AdlEngine_v3 : public AdlEngine_v2 {
+public:
+ virtual ~AdlEngine_v3() { }
+
+protected:
+ AdlEngine_v3(OSystem *syst, const AdlGameDescription *gd);
+
+ // AdlEngine
+ virtual void setupOpcodeTables();
+ virtual Common::String loadMessage(uint idx) const;
+ Common::String getItemDescription(const Item &item) const;
+
+ // AdlEngine_v2
+ virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const;
+
+ void applyDiskOffset(byte &track, byte &sector) const;
+
+ int o3_isVarGT(ScriptEnv &e);
+ int o3_isItemInRoom(ScriptEnv &e);
+ int o3_isNounNotInRoom(ScriptEnv &e);
+ int o3_skipOneCommand(ScriptEnv &e);
+ int o3_moveItem(ScriptEnv &e);
+ int o3_dummy(ScriptEnv &e);
+ int o3_setTextMode(ScriptEnv &e);
+ int o3_setDisk(ScriptEnv &e);
+ int o3_sound(ScriptEnv &e);
+
+ Common::Array<Common::String> _itemDesc;
+ byte _curDisk;
+ Common::Array<DiskOffset> _diskOffsets;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/configure.engine b/engines/adl/configure.engine
new file mode 100644
index 0000000000..844e2b8e6a
--- /dev/null
+++ b/engines/adl/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine adl "ADL" no
diff --git a/engines/adl/console.cpp b/engines/adl/console.cpp
new file mode 100644
index 0000000000..c35e8b02aa
--- /dev/null
+++ b/engines/adl/console.cpp
@@ -0,0 +1,333 @@
+/* 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.
+ *
+ */
+
+#include "common/debug-channels.h"
+
+#include "adl/console.h"
+#include "adl/display.h"
+#include "adl/adl.h"
+
+namespace Adl {
+
+Console::Console(AdlEngine *engine) : GUI::Debugger() {
+ _engine = engine;
+
+ registerCmd("nouns", WRAP_METHOD(Console, Cmd_Nouns));
+ registerCmd("verbs", WRAP_METHOD(Console, Cmd_Verbs));
+ registerCmd("dump_scripts", WRAP_METHOD(Console, Cmd_DumpScripts));
+ registerCmd("valid_cmds", WRAP_METHOD(Console, Cmd_ValidCommands));
+ registerCmd("room", WRAP_METHOD(Console, Cmd_Room));
+ registerCmd("items", WRAP_METHOD(Console, Cmd_Items));
+ registerCmd("give_item", WRAP_METHOD(Console, Cmd_GiveItem));
+ registerCmd("vars", WRAP_METHOD(Console, Cmd_Vars));
+ registerCmd("var", WRAP_METHOD(Console, Cmd_Var));
+}
+
+Common::String Console::toAscii(const Common::String &str) {
+ Common::String ascii(str);
+
+ for (uint i = 0; i < ascii.size(); ++i)
+ ascii.setChar(ascii[i] & 0x7f, i);
+
+ return ascii;
+}
+
+Common::String Console::toAppleWord(const Common::String &str) {
+ Common::String apple(str);
+
+ if (apple.size() > IDI_WORD_SIZE)
+ apple.erase(IDI_WORD_SIZE);
+ apple.toUppercase();
+
+ for (uint i = 0; i < apple.size(); ++i)
+ apple.setChar(APPLECHAR(apple[i]), i);
+
+ while (apple.size() < IDI_WORD_SIZE)
+ apple += APPLECHAR(' ');
+
+ return apple;
+}
+
+bool Console::Cmd_Verbs(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ debugPrintf("Verbs in alphabetical order:\n");
+ printWordMap(_engine->_verbs);
+ return true;
+}
+
+bool Console::Cmd_Nouns(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ debugPrintf("Nouns in alphabetical order:\n");
+ printWordMap(_engine->_nouns);
+ return true;
+}
+
+bool Console::Cmd_ValidCommands(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ WordMap::const_iterator verb, noun;
+ bool is_any;
+
+ for (verb = _engine->_verbs.begin(); verb != _engine->_verbs.end(); ++verb) {
+ for (noun = _engine->_nouns.begin(); noun != _engine->_nouns.end(); ++noun) {
+ if (_engine->isInputValid(verb->_value, noun->_value, is_any) && !is_any)
+ debugPrintf("%s %s\n", toAscii(verb->_key).c_str(), toAscii(noun->_key).c_str());
+ }
+ if (_engine->isInputValid(verb->_value, IDI_ANY, is_any))
+ debugPrintf("%s *\n", toAscii(verb->_key).c_str());
+ }
+ if (_engine->isInputValid(IDI_ANY, IDI_ANY, is_any))
+ debugPrintf("* *\n");
+
+ return true;
+}
+
+bool Console::Cmd_DumpScripts(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ bool oldFlag = DebugMan.isDebugChannelEnabled(kDebugChannelScript);
+
+ DebugMan.enableDebugChannel("Script");
+
+ _engine->_dumpFile = new Common::DumpFile();
+
+ for (byte roomNr = 1; roomNr <= _engine->_state.rooms.size(); ++roomNr) {
+ _engine->loadRoom(roomNr);
+ if (_engine->_roomData.commands.size() != 0) {
+ _engine->_dumpFile->open(Common::String::format("%03d.ADL", roomNr).c_str());
+ _engine->doAllCommands(_engine->_roomData.commands, IDI_ANY, IDI_ANY);
+ _engine->_dumpFile->close();
+ }
+ }
+ _engine->loadRoom(_engine->_state.room);
+
+ _engine->_dumpFile->open("GLOBAL.ADL");
+ _engine->doAllCommands(_engine->_globalCommands, IDI_ANY, IDI_ANY);
+ _engine->_dumpFile->close();
+
+ _engine->_dumpFile->open("RESPONSE.ADL");
+ _engine->doAllCommands(_engine->_roomCommands, IDI_ANY, IDI_ANY);
+ _engine->_dumpFile->close();
+
+ delete _engine->_dumpFile;
+ _engine->_dumpFile = nullptr;
+
+ if (!oldFlag)
+ DebugMan.disableDebugChannel("Script");
+
+ return true;
+}
+
+bool Console::Cmd_Room(int argc, const char **argv) {
+ if (argc > 2) {
+ debugPrintf("Usage: %s [<new_room>]\n", argv[0]);
+ return true;
+ }
+
+ if (argc == 2) {
+ if (!_engine->_canRestoreNow) {
+ debugPrintf("Cannot change rooms right now\n");
+ return true;
+ }
+
+ uint roomCount = _engine->_state.rooms.size();
+ uint room = strtoul(argv[1], NULL, 0);
+ if (room < 1 || room > roomCount) {
+ debugPrintf("Room %u out of valid range [1, %u]\n", room, roomCount);
+ return true;
+ }
+
+ _engine->_state.room = room;
+ _engine->clearScreen();
+ _engine->loadRoom(_engine->_state.room);
+ _engine->showRoom();
+ _engine->_display->updateTextScreen();
+ _engine->_display->updateHiResScreen();
+ }
+
+ debugPrintf("Current room: %u\n", _engine->_state.room);
+
+ return true;
+}
+
+bool Console::Cmd_Items(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ Common::List<Item>::const_iterator item;
+
+ for (item = _engine->_state.items.begin(); item != _engine->_state.items.end(); ++item)
+ printItem(*item);
+
+ return true;
+}
+
+bool Console::Cmd_GiveItem(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: %s <ID | name>\n", argv[0]);
+ return true;
+ }
+
+ Common::List<Item>::iterator item;
+
+ char *end;
+ uint id = strtoul(argv[1], &end, 0);
+
+ if (*end != 0) {
+ Common::Array<Item *> matches;
+
+ Common::String name = toAppleWord(argv[1]);
+
+ if (!_engine->_nouns.contains(name)) {
+ debugPrintf("Item '%s' not found\n", argv[1]);
+ return true;
+ }
+
+ byte noun = _engine->_nouns[name];
+
+ for (item = _engine->_state.items.begin(); item != _engine->_state.items.end(); ++item) {
+ if (item->noun == noun)
+ matches.push_back(&*item);
+ }
+
+ if (matches.size() == 0) {
+ debugPrintf("Item '%s' not found\n", argv[1]);
+ return true;
+ }
+
+ if (matches.size() > 1) {
+ debugPrintf("Multiple matches found, please use item ID:\n");
+ for (uint i = 0; i < matches.size(); ++i)
+ printItem(*matches[i]);
+ return true;
+ }
+
+ matches[0]->room = IDI_ANY;
+ debugPrintf("OK\n");
+ return true;
+ }
+
+ for (item = _engine->_state.items.begin(); item != _engine->_state.items.end(); ++item)
+ if (item->id == id) {
+ item->room = IDI_ANY;
+ debugPrintf("OK\n");
+ return true;
+ }
+
+ debugPrintf("Item %i not found\n", id);
+ return true;
+}
+
+bool Console::Cmd_Vars(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ Common::StringArray vars;
+ for (uint i = 0; i < _engine->_state.vars.size(); ++i)
+ vars.push_back(Common::String::format("%3d: %3d", i, _engine->_state.vars[i]));
+
+ debugPrintf("Variables:\n");
+ debugPrintColumns(vars);
+
+ return true;
+}
+
+bool Console::Cmd_Var(int argc, const char **argv) {
+ if (argc < 2 || argc > 3) {
+ debugPrintf("Usage: %s <index> [<value>]\n", argv[0]);
+ return true;
+ }
+
+ uint varCount = _engine->_state.vars.size();
+ uint var = strtoul(argv[1], NULL, 0);
+
+ if (var >= varCount) {
+ debugPrintf("Variable %u out of valid range [0, %u]\n", var, varCount - 1);
+ return true;
+ }
+
+ if (argc == 3) {
+ uint value = strtoul(argv[2], NULL, 0);
+ _engine->_state.vars[var] = value;
+ }
+
+ debugPrintf("%3d: %3d\n", var, _engine->_state.vars[var]);
+
+ return true;
+}
+
+void Console::printItem(const Item &item) {
+ Common::String name, desc, state;
+
+ if (item.noun > 0)
+ name = _engine->_priNouns[item.noun - 1];
+
+ desc = toAscii(_engine->getItemDescription(item));
+ if (desc.lastChar() == '\r')
+ desc.deleteLastChar();
+
+ switch (item.state) {
+ case IDI_ITEM_NOT_MOVED:
+ state = "PLACED";
+ break;
+ case IDI_ITEM_DROPPED:
+ state = "DROPPED";
+ break;
+ case IDI_ITEM_DOESNT_MOVE:
+ state = "FIXED";
+ break;
+ }
+
+ debugPrintf("%3d %s %-30s %-10s %-8s (%3d, %3d)\n", item.id, name.c_str(), desc.c_str(), _engine->itemRoomStr(item.room).c_str(), state.c_str(), item.position.x, item.position.y);
+}
+
+void Console::printWordMap(const WordMap &wordMap) {
+ Common::StringArray words;
+ WordMap::const_iterator verb;
+
+ for (verb = wordMap.begin(); verb != wordMap.end(); ++verb)
+ words.push_back(Common::String::format("%s: %3d", toAscii(verb->_key).c_str(), wordMap[verb->_key]));
+
+ Common::sort(words.begin(), words.end());
+
+ debugPrintColumns(words);
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/console.h b/engines/adl/console.h
new file mode 100644
index 0000000000..a8c6adc1cc
--- /dev/null
+++ b/engines/adl/console.h
@@ -0,0 +1,65 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_CONSOLE_H
+#define ADL_CONSOLE_H
+
+#include "gui/debugger.h"
+
+#include "common/hashmap.h"
+
+namespace Common {
+class String;
+}
+
+namespace Adl {
+
+class AdlEngine;
+struct Item;
+
+class Console : public GUI::Debugger {
+public:
+ Console(AdlEngine *engine);
+
+ static Common::String toAscii(const Common::String &str);
+ static Common::String toAppleWord(const Common::String &str);
+
+private:
+ bool Cmd_Nouns(int argc, const char **argv);
+ bool Cmd_Verbs(int argc, const char **argv);
+ bool Cmd_DumpScripts(int argc, const char **argv);
+ bool Cmd_ValidCommands(int argc, const char **argv);
+ bool Cmd_Room(int argc, const char **argv);
+ bool Cmd_Items(int argc, const char **argv);
+ bool Cmd_GiveItem(int argc, const char **argv);
+ bool Cmd_Vars(int argc, const char **argv);
+ bool Cmd_Var(int argc, const char **argv);
+
+ void printItem(const Item &item);
+ void printWordMap(const Common::HashMap<Common::String, uint> &wordMap);
+
+ AdlEngine *_engine;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
new file mode 100644
index 0000000000..12405e7c5e
--- /dev/null
+++ b/engines/adl/detection.cpp
@@ -0,0 +1,328 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/translation.h"
+
+#include "graphics/thumbnail.h"
+
+#include "engines/advancedDetector.h"
+
+#include "adl/detection.h"
+
+namespace Adl {
+
+#define GAMEOPTION_COLOR GUIO_GAMEOPTIONS1
+#define GAMEOPTION_SCANLINES GUIO_GAMEOPTIONS2
+#define GAMEOPTION_MONO GUIO_GAMEOPTIONS3
+
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_COLOR,
+ {
+ _s("Color mode"),
+ _s("Use color graphics"),
+ "color",
+ false
+ }
+ },
+
+ {
+ GAMEOPTION_MONO,
+ {
+ _s("Color mode"),
+ _s("Use color graphics"),
+ "color",
+ true
+ }
+ },
+
+ {
+ GAMEOPTION_SCANLINES,
+ {
+ _s("Scanlines"),
+ _s("Show scanlines"),
+ "scanlines",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
+static const PlainGameDescriptor adlGames[] = {
+ { "hires0", "Hi-Res Adventure #0: Mission Asteroid" },
+ { "hires1", "Hi-Res Adventure #1: Mystery House" },
+ { "hires2", "Hi-Res Adventure #2: Wizard and the Princess" },
+ { "hires6", "Hi-Res Adventure #6: The Dark Crystal" },
+ { 0, 0 }
+};
+
+static const AdlGameDescription gameDescriptions[] = {
+ { // Hi-Res Adventure #1: Mystery House - Apple II - 1987 PD release - Plain files
+ {
+ "hires1", 0,
+ {
+ { "ADVENTURE", 0, "22d9e63a11d69fa033ba1738715ad09a", 29952 },
+ { "AUTO LOAD OBJ", 0, "23bfccfe9fcff9b22cf6c41bde9078ac", 12291 },
+ { "MYSTERY.HELLO", 0, "2289b7fea300b506e902a4c597968369", 836 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformApple2GS, // FIXME
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_COLOR, GAMEOPTION_SCANLINES)
+ },
+ GAME_TYPE_HIRES1
+ },
+ { // Hi-Res Adventure #1: Mystery House - Apple II - 1987 PD release - .DSK format
+ {
+ "hires1", 0,
+ {
+ { "MYSTHOUS.DSK", 0, "34ba05e62bf51404c4475c349ca48921", 143360 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformApple2GS, // FIXME
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_COLOR, GAMEOPTION_SCANLINES)
+ },
+ GAME_TYPE_HIRES1
+ },
+ { // Hi-Res Adventure #2: Wizard and the Princess - Apple II - Roberta Williams Anthology
+ {
+ "hires2", 0,
+ {
+ { "WIZARD.DSK", 0, "816fdfc35e25496213c8db40ecf26569", 143360 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformApple2GS, // FIXME
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_MONO, GAMEOPTION_SCANLINES)
+ },
+ GAME_TYPE_HIRES2
+ },
+ { // Hi-Res Adventure #0: Mission Asteroid - Apple II - Roberta Williams Anthology
+ {
+ "hires0", 0,
+ {
+ { "MISSION.NIB", 0, "b158f6f79681d4edd651e1932f9e01d7", 232960 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformApple2GS, // FIXME
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_MONO, GAMEOPTION_SCANLINES)
+ },
+ GAME_TYPE_HIRES0
+ },
+ { // Hi-Res Adventure #6: The Dark Crystal - Apple II - Roberta Williams Anthology
+ {
+ "hires6", 0,
+ {
+ { "DARK1A.DSK", 0, "00c2646d6943d1405717332a6f42d493", 143360 },
+ { "DARK2A.NIB", 0, "271eb92db107e8d5829437f8ba77991e", 232960 },
+ { "DARK1B.NIB", 0, "dbedd736617343ade0e6bead8bf2b10c", 232960 },
+ { "DARK2B.NIB", 0, "cb72044a9b391c4285f4752f746bea2e", 232960 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformApple2GS, // FIXME
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_MONO, GAMEOPTION_SCANLINES)
+ },
+ GAME_TYPE_HIRES6
+ },
+ { AD_TABLE_END_MARKER, GAME_TYPE_NONE }
+};
+
+class AdlMetaEngine : public AdvancedMetaEngine {
+public:
+ AdlMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(AdlGameDescription), adlGames, optionsList) { }
+
+ const char *getName() const {
+ return "ADL";
+ }
+
+ const char *getOriginalCopyright() const {
+ return "Copyright (C) Sierra On-Line";
+ }
+
+ bool hasFeature(MetaEngineFeature f) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ int getMaximumSaveSlot() const { return 'O' - 'A'; }
+ SaveStateList listSaves(const char *target) const;
+ void removeSaveState(const char *target, int slot) const;
+
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
+};
+
+bool AdlMetaEngine::hasFeature(MetaEngineFeature f) const {
+ switch(f) {
+ case kSupportsListSaves:
+ case kSupportsLoadingDuringStartup:
+ case kSupportsDeleteSave:
+ case kSavesSupportMetaInfo:
+ case kSavesSupportThumbnail:
+ case kSavesSupportCreationDate:
+ case kSavesSupportPlayTime:
+ return true;
+ default:
+ return false;
+ }
+}
+
+SaveStateDescriptor AdlMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.s%02d", target, slot);
+ Common::InSaveFile *inFile = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (!inFile)
+ return SaveStateDescriptor();
+
+ if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) {
+ delete inFile;
+ return SaveStateDescriptor();
+ }
+
+ byte saveVersion = inFile->readByte();
+ if (saveVersion != SAVEGAME_VERSION) {
+ delete inFile;
+ return SaveStateDescriptor();
+ }
+
+ char name[SAVEGAME_NAME_LEN] = { };
+ inFile->read(name, sizeof(name) - 1);
+ inFile->readByte();
+
+ if (inFile->eos() || inFile->err()) {
+ delete inFile;
+ return SaveStateDescriptor();
+ }
+
+ SaveStateDescriptor sd(slot, name);
+
+ int year = inFile->readUint16BE();
+ int month = inFile->readByte();
+ int day = inFile->readByte();
+ sd.setSaveDate(year + 1900, month + 1, day);
+
+ int hour = inFile->readByte();
+ int minutes = inFile->readByte();
+ sd.setSaveTime(hour, minutes);
+
+ uint32 playTime = inFile->readUint32BE();
+ sd.setPlayTime(playTime);
+
+ if (inFile->eos() || inFile->err()) {
+ delete inFile;
+ return SaveStateDescriptor();
+ }
+
+ Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*inFile);
+ sd.setThumbnail(thumbnail);
+
+ delete inFile;
+ return sd;
+}
+
+SaveStateList AdlMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray files = saveFileMan->listSavefiles(Common::String(target) + ".s##");
+
+ SaveStateList saveList;
+
+ for (uint i = 0; i < files.size(); ++i) {
+ const Common::String &fileName = files[i];
+ Common::InSaveFile *inFile = saveFileMan->openForLoading(fileName);
+ if (!inFile) {
+ warning("Cannot open save file '%s'", fileName.c_str());
+ continue;
+ }
+
+ if (inFile->readUint32BE() != MKTAG('A', 'D', 'L', ':')) {
+ warning("No header found in '%s'", fileName.c_str());
+ delete inFile;
+ continue;
+ }
+
+ byte saveVersion = inFile->readByte();
+ if (saveVersion != SAVEGAME_VERSION) {
+ warning("Unsupported save game version %i found in '%s'", saveVersion, fileName.c_str());
+ delete inFile;
+ continue;
+ }
+
+ char name[SAVEGAME_NAME_LEN] = { };
+ inFile->read(name, sizeof(name) - 1);
+ delete inFile;
+
+ int slotNum = atoi(fileName.c_str() + fileName.size() - 2);
+ SaveStateDescriptor sd(slotNum, name);
+ saveList.push_back(sd);
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+void AdlMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.s%02d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd);
+Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd);
+Engine *HiRes6Engine_create(OSystem *syst, const AdlGameDescription *gd);
+
+bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
+ if (!gd)
+ return false;
+
+ const AdlGameDescription *adlGd = (const AdlGameDescription *)gd;
+
+ switch (adlGd->gameType) {
+ case GAME_TYPE_HIRES1:
+ *engine = HiRes1Engine_create(syst, adlGd);
+ break;
+ case GAME_TYPE_HIRES2:
+ *engine = HiRes2Engine_create(syst, adlGd);
+ break;
+ case GAME_TYPE_HIRES6:
+ *engine = HiRes6Engine_create(syst, adlGd);
+ break;
+ default:
+ error("Unknown GameType");
+ }
+
+ return true;
+}
+
+} // End of namespace Adl
+
+#if PLUGIN_ENABLED_DYNAMIC(ADL)
+ REGISTER_PLUGIN_DYNAMIC(ADL, PLUGIN_TYPE_ENGINE, Adl::AdlMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(ADL, PLUGIN_TYPE_ENGINE, Adl::AdlMetaEngine);
+#endif
diff --git a/engines/adl/detection.h b/engines/adl/detection.h
new file mode 100644
index 0000000000..533466c094
--- /dev/null
+++ b/engines/adl/detection.h
@@ -0,0 +1,48 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_DETECTION_H
+#define ADL_DETECTION_H
+
+#include "engines/advancedDetector.h"
+
+namespace Adl {
+
+#define SAVEGAME_VERSION 0
+#define SAVEGAME_NAME_LEN 32
+
+enum GameType {
+ GAME_TYPE_NONE,
+ GAME_TYPE_HIRES0,
+ GAME_TYPE_HIRES1,
+ GAME_TYPE_HIRES2,
+ GAME_TYPE_HIRES6
+};
+
+struct AdlGameDescription {
+ ADGameDescription desc;
+ GameType gameType;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp
new file mode 100644
index 0000000000..214f76aeae
--- /dev/null
+++ b/engines/adl/disk.cpp
@@ -0,0 +1,460 @@
+/* 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.
+ *
+ */
+
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/memstream.h"
+
+#include "adl/disk.h"
+
+namespace Adl {
+
+const DataBlockPtr DiskImage_DSK::getDataBlock(uint track, uint sector, uint offset, uint size) const {
+ return Common::SharedPtr<DiskImage::DataBlock>(new DiskImage::DataBlock(this, track, sector, offset, size));
+}
+
+Common::SeekableReadStream *DiskImage_DSK::createReadStream(uint track, uint sector, uint offset, uint size) const {
+ _f->seek((track * _sectorsPerTrack + sector) * _bytesPerSector + offset);
+ Common::SeekableReadStream *stream = _f->readStream(size * _bytesPerSector + _bytesPerSector - offset);
+
+ if (_f->eos() || _f->err())
+ error("Error reading disk image");
+
+ return stream;
+}
+
+bool DiskImage_DSK::open(const Common::String &filename) {
+ assert(!_f->isOpen());
+
+ if (!_f->open(filename))
+ return false;
+
+ uint filesize = _f->size();
+ switch (filesize) {
+ case 143360:
+ _tracks = 35;
+ _sectorsPerTrack = 16;
+ _bytesPerSector = 256;
+ break;
+ default:
+ warning("Unrecognized disk image '%s' of size %d bytes", filename.c_str(), filesize);
+ return false;
+ }
+
+ return true;
+}
+
+const DataBlockPtr DiskImage_NIB::getDataBlock(uint track, uint sector, uint offset, uint size) const {
+ return Common::SharedPtr<DiskImage::DataBlock>(new DiskImage::DataBlock(this, track, sector, offset, size));
+}
+
+Common::SeekableReadStream *DiskImage_NIB::createReadStream(uint track, uint sector, uint offset, uint size) const {
+ _memStream->seek((track * _sectorsPerTrack + sector) * _bytesPerSector + offset);
+ Common::SeekableReadStream *stream = _memStream->readStream(size * _bytesPerSector + _bytesPerSector - offset);
+
+ if (_memStream->eos() || _memStream->err())
+ error("Error reading NIB image");
+
+ return stream;
+}
+
+// 4-and-4 encoding (odd-even)
+static uint8 read44(Common::SeekableReadStream *f) {
+ // 1s in the other fields, so we can just AND
+ uint8 ret = f->readByte();
+ return ((ret << 1) | 1) & f->readByte();
+}
+
+bool DiskImage_NIB::open(const Common::String &filename) {
+ assert(!_f->isOpen());
+
+ if (!_f->open(filename))
+ return false;
+
+ uint filesize = _f->size();
+ switch (filesize) {
+ case 232960:
+ _tracks = 35;
+ _sectorsPerTrack = 16; // we always pad it out
+ _bytesPerSector = 256;
+ break;
+ default:
+ error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), filesize);
+ }
+
+ // starting at 0xaa, 32 is invalid (see below)
+ const byte c_5and3_lookup[] = { 32, 0, 32, 1, 2, 3, 32, 32, 32, 32, 32, 4, 5, 6, 32, 32, 7, 8, 32, 9, 10, 11, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 12, 13, 32, 32, 14, 15, 32, 16, 17, 18, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 19, 20, 32, 21, 22, 23, 32, 32, 32, 32, 32, 24, 25, 26, 32, 32, 27, 28, 32, 29, 30, 31 };
+ // starting at 0x96, 64 is invalid (see below)
+ const byte c_6and2_lookup[] = { 0, 1, 64, 64, 2, 3, 64, 4, 5, 6, 64, 64, 64, 64, 64, 64, 7, 8, 64, 64, 64, 9, 10, 11, 12, 13, 64, 64, 14, 15, 16, 17, 18, 19, 64, 20, 21, 22, 23, 24, 25, 26, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 27, 64, 28, 29, 30, 64, 64, 64, 31, 64, 64, 32, 33, 64, 34, 35, 36, 37, 38, 39, 40, 64, 64, 64, 64, 64, 41, 42, 43, 64, 44, 45, 46, 47, 48, 49, 50, 64, 64, 51, 52, 53, 54, 55, 56, 64, 57, 58, 59, 60, 61, 62, 63 };
+
+ uint32 diskSize = _tracks * _sectorsPerTrack * _bytesPerSector;
+ byte *diskImage = (byte *)calloc(diskSize, 1);
+ _memStream = new Common::MemoryReadStream(diskImage, diskSize, DisposeAfterUse::YES);
+
+ bool sawAddress = false;
+ uint8 volNo, track, sector;
+ bool newStyle;
+
+ while (_f->pos() < _f->size()) {
+ // Read until we find two sync bytes.
+ if (_f->readByte() != 0xd5 || _f->readByte() != 0xaa)
+ continue;
+
+ byte prologue = _f->readByte();
+
+ if (sawAddress && (prologue == 0xb5 || prologue == 0x96)) {
+ warning("NIB: data for %02x/%02x/%02x missing", volNo, track, sector);
+ sawAddress = false;
+ }
+
+ if (!sawAddress) {
+ sawAddress = true;
+ newStyle = false;
+
+ // We should always find the address field first.
+ if (prologue != 0xb5) {
+ // Accept a DOS 3.3(?) header at the start.
+ if (prologue == 0x96) {
+ newStyle = true;
+ } else {
+ error("unknown NIB field prologue %02x", prologue);
+ }
+ }
+
+ volNo = read44(_f);
+ track = read44(_f);
+ sector = read44(_f);
+ uint8 checksum = read44(_f);
+ if ((volNo ^ track ^ sector) != checksum)
+ error("invalid NIB checksum");
+
+ // FIXME: This is a hires0/hires2-specific hack.
+ if (volNo == 0xfe) {
+ if (track == 1)
+ track = 2;
+ else if (track == 2)
+ track = 1;
+ }
+
+ // Epilogue is de/aa plus a gap, but we don't care.
+ continue;
+ }
+
+ sawAddress = false;
+
+ // We should always find the data field after an address field.
+ // TODO: we ignore volNo?
+ byte *output = diskImage + (track * _sectorsPerTrack + sector) * _bytesPerSector;
+
+ if (newStyle) {
+ // We hardcode the DOS 3.3 mapping here. TODO: Do we also need raw/prodos?
+ int raw2dos[16] = { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 };
+ sector = raw2dos[sector];
+ output = diskImage + (track * _sectorsPerTrack + sector) * _bytesPerSector;
+
+ // 6-and-2 uses 342 on-disk bytes
+ byte inbuffer[342];
+ _f->read(inbuffer, 342);
+
+ byte oldVal = 0;
+ for (uint n = 0; n < 342; ++n) {
+ // expand
+ assert(inbuffer[n] >= 0x96); // corrupt file (TODO: assert?)
+ byte val = c_6and2_lookup[inbuffer[n] - 0x96];
+ if (val == 0x40) {
+ error("NIB: invalid nibble value %02x", inbuffer[n]);
+ }
+ // undo checksum
+ oldVal = val ^ oldVal;
+ inbuffer[n] = oldVal;
+ }
+
+ byte checksum = _f->readByte();
+ if (checksum < 0x96 || oldVal != c_6and2_lookup[checksum - 0x96])
+ warning("NIB: checksum mismatch @ (%x, %x)", track, sector);
+
+ for (uint n = 0; n < 256; ++n) {
+ output[n] = inbuffer[86 + n] << 2;
+ if (n < 86) { // use first pair of bits
+ output[n] |= ((inbuffer[n] & 1) << 1);
+ output[n] |= ((inbuffer[n] & 2) >> 1);
+ } else if (n < 86*2) { // second pair
+ output[n] |= ((inbuffer[n-86] & 4) >> 1);
+ output[n] |= ((inbuffer[n-86] & 8) >> 3);
+ } else { // third pair
+ output[n] |= ((inbuffer[n-86*2] & 0x10) >> 3);
+ output[n] |= ((inbuffer[n-86*2] & 0x20) >> 5);
+ }
+ }
+ } else {
+ // 5-and-3 uses 410 on-disk bytes, decoding to just over 256 bytes
+ byte inbuffer[410];
+ _f->read(inbuffer, 410);
+
+ bool truncated = false;
+ byte oldVal = 0;
+ for (uint n = 0; n < 410; ++n) {
+ // expand
+ assert(inbuffer[n] >= 0xaa); // corrupt file (TODO: assert?)
+ if (inbuffer[n] == 0xd5) {
+ // Early end of block.
+ truncated = true;
+ _f->seek(-(410 - n), SEEK_CUR);
+ warning("NIB: early end of block @ 0x%x (%x, %x)", _f->pos(), track, sector);
+ break;
+ }
+ byte val = c_5and3_lookup[inbuffer[n] - 0xaa];
+ if (val == 0x20) {
+ // Badly-encoded nibbles, stop trying to decode here.
+ truncated = true;
+ warning("NIB: bad nibble %02x @ 0x%x (%x, %x)", inbuffer[n], _f->pos(), track, sector);
+ _f->seek(-(410 - n), SEEK_CUR);
+ break;
+ }
+ // undo checksum
+ oldVal = val ^ oldVal;
+ inbuffer[n] = oldVal;
+ }
+ if (!truncated) {
+ byte checksum = _f->readByte();
+ if (checksum < 0xaa || oldVal != c_5and3_lookup[checksum - 0xaa])
+ warning("NIB: checksum mismatch @ (%x, %x)", track, sector);
+ }
+
+ // 8 bytes of nibbles expand to 5 bytes
+ // so we have 51 of these batches (255 bytes), plus 2 bytes of 'leftover' nibbles for byte 256
+ for (uint n = 0; n < 51; ++n) {
+ // e.g. figure 3.18 of Beneath Apple DOS
+ byte lowbits1 = inbuffer[51*3 - n];
+ byte lowbits2 = inbuffer[51*2 - n];
+ byte lowbits3 = inbuffer[51*1 - n];
+ byte lowbits4 = (lowbits1 & 2) << 1 | (lowbits2 & 2) | (lowbits3 & 2) >> 1;
+ byte lowbits5 = (lowbits1 & 1) << 2 | (lowbits2 & 1) << 1 | (lowbits3 & 1);
+ output[250 - 5*n] = (inbuffer[n + 51*3 + 1] << 3) | ((lowbits1 >> 2) & 0x7);
+ output[251 - 5*n] = (inbuffer[n + 51*4 + 1] << 3) | ((lowbits2 >> 2) & 0x7);
+ output[252 - 5*n] = (inbuffer[n + 51*5 + 1] << 3) | ((lowbits3 >> 2) & 0x7);
+ output[253 - 5*n] = (inbuffer[n + 51*6 + 1] << 3) | lowbits4;
+ output[254 - 5*n] = (inbuffer[n + 51*7 + 1] << 3) | lowbits5;
+ }
+ output[255] = (inbuffer[409] << 3) | (inbuffer[0] & 0x7);
+ }
+ }
+
+ return true;
+}
+
+const DataBlockPtr Files_Plain::getDataBlock(const Common::String &filename, uint offset) const {
+ return Common::SharedPtr<Files::DataBlock>(new Files::DataBlock(this, filename, offset));
+}
+
+Common::SeekableReadStream *Files_Plain::createReadStream(const Common::String &filename, uint offset) const {
+ Common::File *f(new Common::File());
+
+ if (!f->open(filename))
+ error("Failed to open '%s'", filename.c_str());
+
+ if (offset == 0)
+ return f;
+ else
+ return new Common::SeekableSubReadStream(f, offset, f->size(), DisposeAfterUse::YES);
+}
+
+Files_DOS33::~Files_DOS33() {
+ delete _disk;
+}
+
+Files_DOS33::Files_DOS33() :
+ _disk(nullptr) {
+}
+
+void Files_DOS33::readSectorList(TrackSector start, Common::Array<TrackSector> &list) {
+ TrackSector index = start;
+
+ while (index.track != 0) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(index.track, index.sector));
+
+ stream->readByte();
+ index.track = stream->readByte();
+ index.sector = stream->readByte();
+
+ stream->seek(9, SEEK_CUR);
+
+ // This only handles sequential files
+ TrackSector ts;
+ ts.track = stream->readByte();
+ ts.sector = stream->readByte();
+
+ while (ts.track != 0) {
+ list.push_back(ts);
+
+ ts.track = stream->readByte();
+ ts.sector = stream->readByte();
+
+ if (stream->err())
+ error("Error reading sector list");
+
+ if (stream->eos())
+ break;
+ }
+ }
+}
+
+void Files_DOS33::readVTOC() {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(0x11, 0x00));
+ stream->readByte();
+ byte track = stream->readByte();
+ byte sector = stream->readByte();
+
+ while (track != 0) {
+ char name[kFilenameLen + 1] = { };
+
+ stream.reset(_disk->createReadStream(track, sector));
+ stream->readByte();
+ track = stream->readByte();
+ sector = stream->readByte();
+ stream->seek(8, SEEK_CUR);
+
+ for (uint i = 0; i < 7; ++i) {
+ TOCEntry entry;
+ TrackSector sectorList;
+ sectorList.track = stream->readByte();
+ sectorList.sector = stream->readByte();
+ entry.type = stream->readByte();
+ stream->read(name, kFilenameLen);
+
+ // Convert to ASCII
+ for (uint j = 0; j < kFilenameLen; j++)
+ name[j] &= 0x7f;
+
+ // Strip trailing spaces
+ for (int j = kFilenameLen - 1; j >= 0; --j) {
+ if (name[j] == ' ')
+ name[j] = 0;
+ else
+ break;
+ }
+
+ entry.totalSectors = stream->readUint16BE();
+
+ if (sectorList.track != 0) {
+ readSectorList(sectorList, entry.sectors);
+ _toc[name] = entry;
+ }
+ }
+ }
+}
+
+const DataBlockPtr Files_DOS33::getDataBlock(const Common::String &filename, uint offset) const {
+ return Common::SharedPtr<Files::DataBlock>(new Files::DataBlock(this, filename, offset));
+}
+
+Common::SeekableReadStream *Files_DOS33::createReadStreamText(const TOCEntry &entry) const {
+ byte *buf = (byte *)malloc(entry.sectors.size() * kSectorSize);
+ byte *p = buf;
+
+ for (uint i = 0; i < entry.sectors.size(); ++i) {
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(entry.sectors[i].track, entry.sectors[i].sector));
+
+ assert(stream->size() == kSectorSize);
+
+ while (true) {
+ byte textChar = stream->readByte();
+
+ if (stream->eos() || textChar == 0)
+ break;
+
+ if (stream->err())
+ error("Error reading text file");
+
+ *p++ = textChar;
+ }
+ }
+
+ return new Common::MemoryReadStream(buf, p - buf, DisposeAfterUse::YES);
+}
+
+Common::SeekableReadStream *Files_DOS33::createReadStreamBinary(const TOCEntry &entry) const {
+ byte *buf = (byte *)malloc(entry.sectors.size() * kSectorSize);
+
+ Common::ScopedPtr<Common::SeekableReadStream> stream(_disk->createReadStream(entry.sectors[0].track, entry.sectors[0].sector));
+
+ if (entry.type == kFileTypeBinary)
+ stream->readUint16LE(); // Skip start address
+
+ uint16 size = stream->readUint16LE();
+ uint16 offset = 0;
+ uint16 sectorIdx = 1;
+
+ while (true) {
+ offset += stream->read(buf + offset, size - offset);
+
+ if (offset == size)
+ break;
+
+ if (stream->err())
+ error("Error reading binary file");
+
+ assert(stream->eos());
+
+ if (sectorIdx == entry.sectors.size())
+ error("Not enough sectors for binary file size");
+
+ stream.reset(_disk->createReadStream(entry.sectors[sectorIdx].track, entry.sectors[sectorIdx].sector));
+ ++sectorIdx;
+ }
+
+ return new Common::MemoryReadStream(buf, size, DisposeAfterUse::YES);
+}
+
+Common::SeekableReadStream *Files_DOS33::createReadStream(const Common::String &filename, uint offset) const {
+ if (!_toc.contains(filename))
+ error("Failed to locate '%s'", filename.c_str());
+
+ const TOCEntry &entry = _toc[filename];
+
+ Common::SeekableReadStream *stream;
+
+ switch(entry.type) {
+ case kFileTypeText:
+ stream = createReadStreamText(entry);
+ break;
+ case kFileTypeAppleSoft:
+ case kFileTypeBinary:
+ stream = createReadStreamBinary(entry);
+ break;
+ default:
+ error("Unsupported file type %i", entry.type);
+ }
+
+ return new Common::SeekableSubReadStream(stream, offset, stream->size(), DisposeAfterUse::YES);
+}
+
+bool Files_DOS33::open(const Common::String &filename) {
+ _disk = new DiskImage_DSK();
+ if (!_disk->open(filename))
+ return false;
+
+ readVTOC();
+ return true;
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/disk.h b/engines/adl/disk.h
new file mode 100644
index 0000000000..43b9e387ba
--- /dev/null
+++ b/engines/adl/disk.h
@@ -0,0 +1,188 @@
+/* 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.
+ *
+ */
+
+#include "common/ptr.h"
+#include "common/file.h"
+#include "common/debug.h"
+
+#ifndef ADL_DISK_H
+#define ADL_DISK_H
+
+namespace Common {
+class SeekableReadStream;
+class String;
+}
+
+namespace Adl {
+
+class DataBlock {
+public:
+ virtual ~DataBlock() { }
+
+ virtual Common::SeekableReadStream *createReadStream() const = 0;
+};
+
+typedef Common::SharedPtr<DataBlock> DataBlockPtr;
+typedef Common::ScopedPtr<Common::SeekableReadStream> StreamPtr;
+
+class Files {
+public:
+ virtual ~Files() { }
+
+ virtual const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const = 0;
+ virtual Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const = 0;
+
+protected:
+ class DataBlock : public Adl::DataBlock {
+ public:
+ DataBlock(const Files *files, const Common::String &filename, uint offset) :
+ _files(files),
+ _filename(filename),
+ _offset(offset) { }
+
+ Common::SeekableReadStream *createReadStream() const {
+ return _files->createReadStream(_filename, _offset);
+ }
+
+ private:
+ const Common::String _filename;
+ uint _offset;
+ const Files *_files;
+ };
+};
+
+class DiskImage {
+public:
+ DiskImage() :
+ _tracks(0),
+ _sectorsPerTrack(0),
+ _bytesPerSector(0) {
+ _f = new Common::File();
+ }
+
+ virtual ~DiskImage() {
+ delete _f;
+ }
+
+ virtual bool open(const Common::String &filename) = 0;
+ virtual const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const = 0;
+ virtual Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0) const = 0;
+
+protected:
+ class DataBlock : public Adl::DataBlock {
+ public:
+ DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size) :
+ _track(track),
+ _sector(sector),
+ _offset(offset),
+ _size(size),
+ _disk(disk) { }
+
+ Common::SeekableReadStream *createReadStream() const {
+ return _disk->createReadStream(_track, _sector, _offset, _size);
+ }
+
+ private:
+ uint _track, _sector, _offset, _size;
+ const DiskImage *_disk;
+ };
+
+ Common::File *_f;
+ uint _tracks, _sectorsPerTrack, _bytesPerSector;
+};
+
+// Data in plain files
+class Files_Plain : public Files {
+public:
+ const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const;
+ Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const;
+};
+
+// .DSK disk image - 35 tracks, 16 sectors per track, 256 bytes per sector
+class DiskImage_DSK : public DiskImage {
+public:
+ bool open(const Common::String &filename);
+ const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const;
+ Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0) const;
+};
+
+// .NIB disk image
+class DiskImage_NIB : public DiskImage {
+public:
+ DiskImage_NIB() : _memStream(nullptr) { }
+ virtual ~DiskImage_NIB() {
+ delete _memStream;
+ }
+
+ bool open(const Common::String &filename);
+ const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const;
+ Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0) const;
+
+private:
+ Common::SeekableReadStream *_memStream;
+};
+
+// Data in files contained in Apple DOS 3.3 disk image
+class Files_DOS33 : public Files {
+public:
+ Files_DOS33();
+ ~Files_DOS33();
+
+ bool open(const Common::String &filename);
+ const DataBlockPtr getDataBlock(const Common::String &filename, uint offset = 0) const;
+ Common::SeekableReadStream *createReadStream(const Common::String &filename, uint offset = 0) const;
+
+private:
+ enum FileType {
+ kFileTypeText = 0,
+ kFileTypeAppleSoft = 2,
+ kFileTypeBinary = 4
+ };
+
+ enum {
+ kSectorSize = 256,
+ kFilenameLen = 30
+ };
+
+ struct TrackSector {
+ byte track;
+ byte sector;
+ };
+
+ struct TOCEntry {
+ byte type;
+ uint16 totalSectors;
+ Common::Array<TrackSector> sectors;
+ };
+
+ void readVTOC();
+ void readSectorList(TrackSector start, Common::Array<TrackSector> &list);
+ Common::SeekableReadStream *createReadStreamText(const TOCEntry &entry) const;
+ Common::SeekableReadStream *createReadStreamBinary(const TOCEntry &entry) const;
+
+ DiskImage *_disk;
+ Common::HashMap<Common::String, TOCEntry> _toc;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp
new file mode 100644
index 0000000000..b7f6eb9923
--- /dev/null
+++ b/engines/adl/display.cpp
@@ -0,0 +1,545 @@
+/* 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.
+ *
+ */
+
+#include "common/stream.h"
+#include "common/rect.h"
+#include "common/system.h"
+#include "common/str.h"
+#include "common/config-manager.h"
+
+#include "graphics/surface.h"
+#include "graphics/palette.h"
+#include "graphics/thumbnail.h"
+
+#include "engines/util.h"
+
+#include "adl/display.h"
+
+namespace Adl {
+
+// This implements the Apple II "Hi-Res" display mode
+
+#define DISPLAY_PITCH (DISPLAY_WIDTH / 7)
+#define DISPLAY_SIZE (DISPLAY_PITCH * DISPLAY_HEIGHT)
+
+#define TEXT_BUF_SIZE (TEXT_WIDTH * TEXT_HEIGHT)
+
+#define COLOR_PALETTE_ENTRIES 8
+static const byte colorPalette[COLOR_PALETTE_ENTRIES * 3] = {
+ 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff,
+ 0xc7, 0x34, 0xff,
+ 0x38, 0xcb, 0x00,
+ 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff,
+ 0x0d, 0xa1, 0xff,
+ 0xf2, 0x5e, 0x00
+};
+
+// Corresponding color in second palette
+#define PAL2(X) ((X) | 0x04)
+
+// Alternate color for odd pixel rows (for scanlines)
+#define ALTCOL(X) ((X) | 0x08)
+
+// Green monochrome palette
+#define MONO_PALETTE_ENTRIES 2
+static const byte monoPalette[MONO_PALETTE_ENTRIES * 3] = {
+ 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0x01
+};
+
+// Uppercase-only Apple II font (manually created).
+static const byte font[64][5] = {
+ { 0x7c, 0x82, 0xba, 0xb2, 0x9c }, { 0xf8, 0x24, 0x22, 0x24, 0xf8 }, // @A
+ { 0xfe, 0x92, 0x92, 0x92, 0x6c }, { 0x7c, 0x82, 0x82, 0x82, 0x44 }, // BC
+ { 0xfe, 0x82, 0x82, 0x82, 0x7c }, { 0xfe, 0x92, 0x92, 0x92, 0x82 }, // DE
+ { 0xfe, 0x12, 0x12, 0x12, 0x02 }, { 0x7c, 0x82, 0x82, 0xa2, 0xe2 }, // FG
+ { 0xfe, 0x10, 0x10, 0x10, 0xfe }, { 0x00, 0x82, 0xfe, 0x82, 0x00 }, // HI
+ { 0x40, 0x80, 0x80, 0x80, 0x7e }, { 0xfe, 0x10, 0x28, 0x44, 0x82 }, // JK
+ { 0xfe, 0x80, 0x80, 0x80, 0x80 }, { 0xfe, 0x04, 0x18, 0x04, 0xfe }, // LM
+ { 0xfe, 0x08, 0x10, 0x20, 0xfe }, { 0x7c, 0x82, 0x82, 0x82, 0x7c }, // NO
+ { 0xfe, 0x12, 0x12, 0x12, 0x0c }, { 0x7c, 0x82, 0xa2, 0x42, 0xbc }, // PQ
+ { 0xfe, 0x12, 0x32, 0x52, 0x8c }, { 0x4c, 0x92, 0x92, 0x92, 0x64 }, // RS
+ { 0x02, 0x02, 0xfe, 0x02, 0x02 }, { 0x7e, 0x80, 0x80, 0x80, 0x7e }, // TU
+ { 0x3e, 0x40, 0x80, 0x40, 0x3e }, { 0xfe, 0x40, 0x30, 0x40, 0xfe }, // VW
+ { 0xc6, 0x28, 0x10, 0x28, 0xc6 }, { 0x06, 0x08, 0xf0, 0x08, 0x06 }, // XY
+ { 0xc2, 0xa2, 0x92, 0x8a, 0x86 }, { 0xfe, 0xfe, 0x82, 0x82, 0x82 }, // Z[
+ { 0x04, 0x08, 0x10, 0x20, 0x40 }, { 0x82, 0x82, 0x82, 0xfe, 0xfe }, // \]
+ { 0x20, 0x10, 0x08, 0x10, 0x20 }, { 0x80, 0x80, 0x80, 0x80, 0x80 }, // ^_
+ { 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xbe, 0x00, 0x00 }, // !
+ { 0x00, 0x0e, 0x00, 0x0e, 0x00 }, { 0x28, 0xfe, 0x28, 0xfe, 0x28 }, // "#
+ { 0x48, 0x54, 0xfe, 0x54, 0x24 }, { 0x46, 0x26, 0x10, 0xc8, 0xc4 }, // $%
+ { 0x6c, 0x92, 0xac, 0x40, 0xa0 }, { 0x00, 0x00, 0x0e, 0x00, 0x00 }, // &'
+ { 0x38, 0x44, 0x82, 0x00, 0x00 }, { 0x00, 0x00, 0x82, 0x44, 0x38 }, // ()
+ { 0x44, 0x28, 0xfe, 0x28, 0x44 }, { 0x10, 0x10, 0x7c, 0x10, 0x10 }, // *+
+ { 0x00, 0x80, 0x60, 0x00, 0x00 }, { 0x10, 0x10, 0x10, 0x10, 0x10 }, // ,-
+ { 0x00, 0x00, 0x80, 0x00, 0x00 }, { 0x40, 0x20, 0x10, 0x08, 0x04 }, // ./
+ { 0x7c, 0xa2, 0x92, 0x8a, 0x7c }, { 0x00, 0x84, 0xfe, 0x80, 0x00 }, // 01
+ { 0xc4, 0xa2, 0x92, 0x92, 0x8c }, { 0x42, 0x82, 0x92, 0x9a, 0x66 }, // 23
+ { 0x30, 0x28, 0x24, 0xfe, 0x20 }, { 0x4e, 0x8a, 0x8a, 0x8a, 0x72 }, // 45
+ { 0x78, 0x94, 0x92, 0x92, 0x62 }, { 0x02, 0xe2, 0x12, 0x0a, 0x06 }, // 67
+ { 0x6c, 0x92, 0x92, 0x92, 0x6c }, { 0x8c, 0x92, 0x92, 0x52, 0x3c }, // 89
+ { 0x00, 0x00, 0x28, 0x00, 0x00 }, { 0x00, 0x80, 0x68, 0x00, 0x00 }, // :;
+ { 0x10, 0x28, 0x44, 0x82, 0x00 }, { 0x28, 0x28, 0x28, 0x28, 0x28 }, // <=
+ { 0x00, 0x82, 0x44, 0x28, 0x10 }, { 0x04, 0x02, 0xb2, 0x0a, 0x04 } // >?
+};
+
+Display::Display() :
+ _mode(DISPLAY_MODE_TEXT),
+ _cursorPos(0),
+ _showCursor(false) {
+
+ initGraphics(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, true);
+
+ _monochrome = !ConfMan.getBool("color");
+ _scanlines = ConfMan.getBool("scanlines");
+
+ if (_monochrome)
+ g_system->getPaletteManager()->setPalette(monoPalette, 0, MONO_PALETTE_ENTRIES);
+ else
+ g_system->getPaletteManager()->setPalette(colorPalette, 0, COLOR_PALETTE_ENTRIES);
+
+ showScanlines(_scanlines);
+
+ _frameBuf = new byte[DISPLAY_SIZE];
+ memset(_frameBuf, 0, DISPLAY_SIZE);
+ _frameBufSurface = new Graphics::Surface;
+ // We need 2x scaling to properly render the half-pixel shift
+ // of the second palette
+ _frameBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8());
+
+ _textBuf = new byte[TEXT_BUF_SIZE];
+ memset(_textBuf, APPLECHAR(' '), TEXT_BUF_SIZE);
+ _textBufSurface = new Graphics::Surface;
+ // For ease of copying, also use 2x scaling here
+ _textBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8());
+
+ createFont();
+}
+
+Display::~Display() {
+ delete[] _frameBuf;
+ _frameBufSurface->free();
+ delete _frameBufSurface;
+
+ delete[] _textBuf;
+ _textBufSurface->free();
+ delete _textBufSurface;
+
+ _font->free();
+ delete _font;
+}
+
+void Display::setMode(DisplayMode mode) {
+ _mode = mode;
+
+ if (_mode == DISPLAY_MODE_TEXT || _mode == DISPLAY_MODE_MIXED)
+ updateTextScreen();
+ if (_mode == DISPLAY_MODE_HIRES || _mode == DISPLAY_MODE_MIXED)
+ updateHiResScreen();
+}
+
+void Display::updateTextScreen() {
+ updateTextSurface();
+
+ if (_mode == DISPLAY_MODE_TEXT)
+ g_system->copyRectToScreen(_textBufSurface->getPixels(), _textBufSurface->pitch, 0, 0, _textBufSurface->w, _textBufSurface->h);
+ else if (_mode == DISPLAY_MODE_MIXED)
+ g_system->copyRectToScreen(_textBufSurface->getBasePtr(0, _textBufSurface->h - 4 * 8 * 2), _textBufSurface->pitch, 0, _textBufSurface->h - 4 * 8 * 2, _textBufSurface->w, 4 * 8 * 2);
+
+ g_system->updateScreen();
+}
+
+void Display::updateHiResScreen() {
+ updateHiResSurface();
+
+ if (_mode == DISPLAY_MODE_HIRES)
+ g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h);
+ else if (_mode == DISPLAY_MODE_MIXED)
+ g_system->copyRectToScreen(_frameBufSurface->getPixels(), _frameBufSurface->pitch, 0, 0, _frameBufSurface->w, _frameBufSurface->h - 4 * 8 * 2);
+
+ g_system->updateScreen();
+}
+
+bool Display::saveThumbnail(Common::WriteStream &out) {
+ if (_scanlines) {
+ showScanlines(false);
+ g_system->updateScreen();
+ }
+
+ bool retval = Graphics::saveThumbnail(out);
+
+ if (_scanlines) {
+ showScanlines(true);
+ g_system->updateScreen();
+ }
+
+ return retval;
+}
+
+void Display::loadFrameBuffer(Common::ReadStream &stream) {
+ byte *dst = _frameBuf;
+ for (uint j = 0; j < 8; ++j) {
+ for (uint i = 0; i < 8; ++i) {
+ stream.read(dst, DISPLAY_PITCH);
+ dst += DISPLAY_PITCH * 64;
+ stream.read(dst, DISPLAY_PITCH);
+ dst += DISPLAY_PITCH * 64;
+ stream.read(dst, DISPLAY_PITCH);
+ stream.readUint32LE();
+ stream.readUint32LE();
+ dst -= DISPLAY_PITCH * 120;
+ }
+ dst -= DISPLAY_PITCH * 63;
+ }
+
+ if (stream.eos() || stream.err())
+ error("Failed to read frame buffer");
+}
+
+void Display::putPixel(const Common::Point &p, byte color) {
+ byte offset = p.x / 7;
+ byte mask = 0x80 | (1 << (p.x % 7));
+
+ // Since white and black are in both palettes, we leave
+ // the palette bit alone
+ if ((color & 0x7f) == 0x7f || (color & 0x7f) == 0)
+ mask &= 0x7f;
+
+ // Adjust colors starting with bits '01' or '10' for
+ // odd offsets
+ if (offset & 1) {
+ byte c = color << 1;
+ if (c >= 0x40 && c < 0xc0)
+ color ^= 0x7f;
+ }
+
+ writeFrameBuffer(p, color, mask);
+}
+
+void Display::setPixelBit(const Common::Point &p, byte color) {
+ writeFrameBuffer(p, color, 1 << (p.x % 7));
+}
+
+void Display::setPixelPalette(const Common::Point &p, byte color) {
+ writeFrameBuffer(p, color, 0x80);
+}
+
+bool Display::getPixelBit(const Common::Point &p) const {
+ byte *b = _frameBuf + p.y * DISPLAY_PITCH + p.x / 7;
+ return *b & (1 << (p.x % 7));
+}
+
+void Display::clear(byte color) {
+ byte val = 0;
+
+ byte c = color << 1;
+ if (c >= 0x40 && c < 0xc0)
+ val = 0x7f;
+
+ for (uint i = 0; i < DISPLAY_SIZE; ++i) {
+ _frameBuf[i] = color;
+ color ^= val;
+ }
+}
+
+void Display::home() {
+ memset(_textBuf, APPLECHAR(' '), TEXT_BUF_SIZE);
+ _cursorPos = 0;
+}
+
+void Display::moveCursorForward() {
+ ++_cursorPos;
+
+ if (_cursorPos >= TEXT_BUF_SIZE)
+ scrollUp();
+}
+
+void Display::moveCursorBackward() {
+ if (_cursorPos > 0)
+ --_cursorPos;
+}
+
+void Display::moveCursorTo(const Common::Point &pos) {
+ _cursorPos = pos.y * TEXT_WIDTH + pos.x;
+
+ if (_cursorPos >= TEXT_BUF_SIZE)
+ error("Cursor position (%i, %i) out of bounds", pos.x, pos.y);
+}
+
+// FIXME: This does not currently update the surfaces
+void Display::printChar(char c) {
+ if (c == APPLECHAR('\r'))
+ _cursorPos = (_cursorPos / TEXT_WIDTH + 1) * TEXT_WIDTH;
+ else if ((byte)c < 0x80 || (byte)c >= 0xa0) {
+ setCharAtCursor(c);
+ ++_cursorPos;
+ }
+
+ if (_cursorPos == TEXT_BUF_SIZE)
+ scrollUp();
+}
+
+void Display::printString(const Common::String &str) {
+ Common::String::const_iterator c;
+ for (c = str.begin(); c != str.end(); ++c)
+ printChar(*c);
+
+ updateTextScreen();
+}
+
+void Display::printAsciiString(const Common::String &str) {
+ Common::String aStr;
+
+ Common::String::const_iterator it;
+ for (it = str.begin(); it != str.end(); ++it)
+ aStr += APPLECHAR(*it);
+
+ printString(aStr);
+}
+
+void Display::setCharAtCursor(byte c) {
+ _textBuf[_cursorPos] = c;
+}
+
+void Display::showCursor(bool enable) {
+ _showCursor = enable;
+}
+
+void Display::writeFrameBuffer(const Common::Point &p, byte color, byte mask) {
+ byte *b = _frameBuf + p.y * DISPLAY_PITCH + p.x / 7;
+ color ^= *b;
+ color &= mask;
+ *b ^= color;
+}
+
+void Display::showScanlines(bool enable) {
+ byte pal[COLOR_PALETTE_ENTRIES * 3] = { };
+
+ if (enable)
+ g_system->getPaletteManager()->setPalette(pal, COLOR_PALETTE_ENTRIES, COLOR_PALETTE_ENTRIES);
+ else {
+ g_system->getPaletteManager()->grabPalette(pal, 0, COLOR_PALETTE_ENTRIES);
+ g_system->getPaletteManager()->setPalette(pal, COLOR_PALETTE_ENTRIES, COLOR_PALETTE_ENTRIES);
+ }
+}
+
+static byte processColorBits(uint16 &bits, bool &odd, bool secondPal) {
+ byte color = 0;
+
+ switch (bits & 0x7) {
+ case 0x3: // 011 (white)
+ case 0x6: // 110
+ case 0x7: // 111
+ color = 1;
+ break;
+ case 0x2: // 010 (color)
+ color = 2 + odd;
+ break;
+ case 0x5: // 101 (color)
+ color = 2 + !odd;
+ }
+
+ if (secondPal)
+ color = PAL2(color);
+
+ odd = !odd;
+ bits >>= 1;
+
+ return color;
+}
+
+static void renderPixelRowColor(byte *dst, byte *src) {
+ uint16 bits = (src[0] & 0x7f) << 1;
+ byte pal = src[0] >> 7;
+
+ if (pal != 0)
+ *dst++ = 0;
+
+ bool odd = false;
+
+ for (uint i = 0; i < DISPLAY_PITCH; ++i) {
+ if (i != DISPLAY_PITCH - 1) {
+ bits |= (src[i + 1] & 0x7f) << 8;
+ pal |= (src[i + 1] >> 7) << 1;
+ }
+
+ // For the first 6 bits in the block we draw two pixels
+ for (uint j = 0; j < 6; ++j) {
+ byte color = processColorBits(bits, odd, pal & 1);
+ *dst++ = color;
+ *dst++ = color;
+ }
+
+ // Last bit of the block, draw one, two or three pixels
+ byte color = processColorBits(bits, odd, pal & 1);
+
+ // Draw the first pixel
+ *dst++ = color;
+
+ switch (pal) {
+ case 0x0:
+ case 0x3:
+ // If palette stays the same, draw a second pixel
+ *dst++ = color;
+ break;
+ case 0x2:
+ // If we're moving from first to second palette,
+ // draw a second pixel, and a third in the second
+ // palette.
+ *dst++ = color;
+ *dst++ = PAL2(color);
+ }
+
+ pal >>= 1;
+ }
+}
+
+static void renderPixelRowMono(byte *dst, byte *src) {
+ byte pal = src[0] >> 7;
+
+ if (pal != 0)
+ *dst++ = 0;
+
+ for (uint i = 0; i < DISPLAY_PITCH; ++i) {
+ if (i != DISPLAY_PITCH - 1)
+ pal |= (src[i + 1] >> 7) << 1;
+
+ for (uint j = 0; j < 6; ++j) {
+ bool color = src[i] & (1 << j);
+ *dst++ = color;
+ *dst++ = color;
+ }
+
+ bool color = src[i] & (1 << 6);
+
+ *dst++ = color;
+
+ switch (pal) {
+ case 0x0:
+ case 0x3:
+ *dst++ = color;
+ break;
+ case 0x2:
+ *dst++ = color;
+ *dst++ = color;
+ }
+
+ pal >>= 1;
+ }
+}
+
+static void copyEvenSurfaceRows(Graphics::Surface &surf) {
+ byte *src = (byte *)surf.getPixels();
+
+ for (uint y = 0; y < surf.h / 2; ++y) {
+ byte *dst = src + surf.pitch;
+ for (uint x = 0; x < surf.w; ++x)
+ dst[x] = ALTCOL(src[x]);
+ src += surf.pitch * 2;
+ }
+}
+
+void Display::updateHiResSurface() {
+ byte *src = _frameBuf;
+ byte *dst = (byte *)_frameBufSurface->getPixels();
+
+ for (uint i = 0; i < DISPLAY_HEIGHT; ++i) {
+ if (_monochrome)
+ renderPixelRowMono(dst, src);
+ else
+ renderPixelRowColor(dst, src);
+ src += DISPLAY_PITCH;
+ dst += _frameBufSurface->pitch * 2;
+ }
+
+ copyEvenSurfaceRows(*_frameBufSurface);
+}
+
+void Display::updateTextSurface() {
+ for (uint row = 0; row < 24; ++row)
+ for (uint col = 0; col < TEXT_WIDTH; ++col) {
+ uint charPos = row * TEXT_WIDTH + col;
+ char c = _textBuf[row * TEXT_WIDTH + col];
+
+ if (charPos == _cursorPos && _showCursor)
+ c = (c & 0x3f) | 0x40;
+
+ Common::Rect r(7 * 2, 8 * 2);
+ r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2);
+
+ if (!(c & 0x80)) {
+ if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1))
+ r.translate(0, 4 * 8 * 2);
+ }
+
+ _textBufSurface->copyRectToSurface(*_font, col * 7 * 2, row * 8 * 2, r);
+ }
+}
+
+void Display::drawChar(byte c, int x, int y) {
+ byte *buf = (byte *)_font->getPixels() + y * _font->pitch + x;
+
+ for (uint row = 0; row < 8; ++row) {
+ for (uint col = 1; col < 6; ++col) {
+ if (font[c][col - 1] & (1 << row)) {
+ buf[col * 2] = 1;
+ buf[col * 2 + 1] = 1;
+ }
+ }
+
+ buf += 2 * _font->pitch;
+ }
+}
+
+void Display::createFont() {
+ _font = new Graphics::Surface;
+ _font->create(16 * 7 * 2, 4 * 8 * 2 * 2, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (uint i = 0; i < 4; ++i)
+ for (uint j = 0; j < 16; ++j)
+ drawChar(i * 16 + j, j * 7 * 2, i * 8 * 2);
+
+ // Create inverted font
+ byte *buf = (byte *)_font->getPixels();
+ byte *bufInv = buf + (_font->h / 2) * _font->pitch;
+
+ for (uint row = 0; row < _font->h / 2; row += 2) {
+ for (uint col = 0; col < _font->w; ++col)
+ bufInv[col] = (buf[col] ? 0 : 1);
+
+ buf += _font->pitch * 2;
+ bufInv += _font->pitch * 2;
+ }
+
+ copyEvenSurfaceRows(*_font);
+}
+
+void Display::scrollUp() {
+ memmove(_textBuf, _textBuf + TEXT_WIDTH, TEXT_BUF_SIZE - TEXT_WIDTH);
+ memset(_textBuf + TEXT_BUF_SIZE - TEXT_WIDTH, APPLECHAR(' '), TEXT_WIDTH);
+ if (_cursorPos >= TEXT_WIDTH)
+ _cursorPos -= TEXT_WIDTH;
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/display.h b/engines/adl/display.h
new file mode 100644
index 0000000000..bc27b7cb6b
--- /dev/null
+++ b/engines/adl/display.h
@@ -0,0 +1,109 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_DISPLAY_H
+#define ADL_DISPLAY_H
+
+#include <common/types.h>
+
+namespace Common {
+class ReadStream;
+class WriteStream;
+class String;
+struct Point;
+}
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace Adl {
+
+#define DISPLAY_WIDTH 280
+#define DISPLAY_HEIGHT 192
+#define TEXT_WIDTH 40
+#define TEXT_HEIGHT 24
+
+enum DisplayMode {
+ DISPLAY_MODE_HIRES,
+ DISPLAY_MODE_TEXT,
+ DISPLAY_MODE_MIXED
+};
+
+#define APPLECHAR(C) ((char)((C) | 0x80))
+
+class Display {
+public:
+ Display();
+ ~Display();
+
+ void setMode(DisplayMode mode);
+ void updateTextScreen();
+ void updateHiResScreen();
+ bool saveThumbnail(Common::WriteStream &out);
+
+ // Graphics
+ void loadFrameBuffer(Common::ReadStream &stream);
+ void putPixel(const Common::Point &p, byte color);
+ void setPixelBit(const Common::Point &p, byte color);
+ void setPixelPalette(const Common::Point &p, byte color);
+ bool getPixelBit(const Common::Point &p) const;
+ void clear(byte color);
+
+ // Text
+ void home();
+ void moveCursorTo(const Common::Point &pos);
+ void moveCursorForward();
+ void moveCursorBackward();
+ void printChar(char c);
+ void printString(const Common::String &str);
+ void printAsciiString(const Common::String &str);
+ void setCharAtCursor(byte c);
+ void showCursor(bool enable);
+
+private:
+ void writeFrameBuffer(const Common::Point &p, byte color, byte mask);
+ void updateHiResSurface();
+ void showScanlines(bool enable);
+
+ void updateTextSurface();
+ void drawChar(byte c, int x, int y);
+ void createFont();
+ void scrollUp();
+
+ DisplayMode _mode;
+
+ byte *_frameBuf;
+ Graphics::Surface *_frameBufSurface;
+ bool _scanlines;
+ bool _monochrome;
+
+ byte *_textBuf;
+ Graphics::Surface *_textBufSurface;
+ Graphics::Surface *_font;
+ uint _cursorPos;
+ bool _showCursor;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/graphics.cpp b/engines/adl/graphics.cpp
new file mode 100644
index 0000000000..f9af442a9f
--- /dev/null
+++ b/engines/adl/graphics.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.
+ *
+ */
+
+#include "common/stream.h"
+#include "common/rect.h"
+
+#include "adl/display.h"
+#include "adl/graphics.h"
+
+namespace Adl {
+
+// Draws a four-connected line
+void GraphicsMan::drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const {
+ int16 deltaX = p2.x - p1.x;
+ int8 xStep = 1;
+
+ if (deltaX < 0) {
+ deltaX = -deltaX;
+ xStep = -1;
+ }
+
+ int16 deltaY = p2.y - p1.y;
+ int8 yStep = -1;
+
+ if (deltaY > 0) {
+ deltaY = -deltaY;
+ yStep = 1;
+ }
+
+ Common::Point p(p1);
+ int16 steps = deltaX - deltaY + 1;
+ int16 err = deltaX + deltaY;
+
+ while (true) {
+ _display.putPixel(p, color);
+
+ if (--steps == 0)
+ return;
+
+ if (err < 0) {
+ p.y += yStep;
+ err += deltaX;
+ } else {
+ p.x += xStep;
+ err += deltaY;
+ }
+ }
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/graphics.h b/engines/adl/graphics.h
new file mode 100644
index 0000000000..aab807696c
--- /dev/null
+++ b/engines/adl/graphics.h
@@ -0,0 +1,76 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_PICTURE_H
+#define ADL_PICTURE_H
+
+namespace Common {
+class SeekableReadStream;
+struct Point;
+}
+
+namespace Adl {
+
+class Display;
+
+class GraphicsMan {
+public:
+ virtual ~GraphicsMan() { }
+ virtual void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) = 0;
+
+protected:
+ GraphicsMan(Display &display) : _display(display) { }
+ void drawLine(const Common::Point &p1, const Common::Point &p2, byte color) const;
+
+ Display &_display;
+};
+
+class Graphics_v1 : public GraphicsMan {
+public:
+ Graphics_v1(Display &display) : GraphicsMan(display) { }
+ void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos);
+ void drawCorners(Common::ReadStream &corners, const Common::Point &pos, byte rotation = 0, byte scaling = 1, byte color = 0x7f) const;
+
+private:
+ void drawCornerPixel(Common::Point &p, byte color, byte bits, byte quadrant) const;
+};
+
+class Graphics_v2 : public GraphicsMan {
+public:
+ Graphics_v2(Display &display) : GraphicsMan(display), _color(0) { }
+ void drawPic(Common::SeekableReadStream &pic, const Common::Point &pos);
+
+private:
+ void clear();
+ void drawCorners(Common::SeekableReadStream &pic, bool yFirst);
+ void drawRelativeLines(Common::SeekableReadStream &pic);
+ void drawAbsoluteLines(Common::SeekableReadStream &pic);
+ void fillRow(const Common::Point &p, bool fillBit, byte pattern);
+ void fill(Common::SeekableReadStream &pic);
+
+ byte _color;
+ Common::Point _offset;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/graphics_v1.cpp b/engines/adl/graphics_v1.cpp
new file mode 100644
index 0000000000..29c5ef47af
--- /dev/null
+++ b/engines/adl/graphics_v1.cpp
@@ -0,0 +1,120 @@
+/* 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.
+ *
+ */
+
+#include "common/stream.h"
+#include "common/rect.h"
+#include "common/textconsole.h"
+
+#include "adl/display.h"
+#include "adl/graphics.h"
+
+namespace Adl {
+
+void Graphics_v1::drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) {
+ byte x, y;
+ bool bNewLine = false;
+ byte oldX = 0, oldY = 0;
+ while (1) {
+ x = pic.readByte();
+ y = pic.readByte();
+
+ if (pic.err() || pic.eos())
+ error("Error reading picture");
+
+ if (x == 0xff && y == 0xff)
+ return;
+
+ if (x == 0 && y == 0) {
+ bNewLine = true;
+ continue;
+ }
+
+ x += pos.x;
+ y += pos.y;
+
+ if (y > 160)
+ y = 160;
+
+ if (bNewLine) {
+ _display.putPixel(Common::Point(x, y), 0x7f);
+ bNewLine = false;
+ } else {
+ drawLine(Common::Point(oldX, oldY), Common::Point(x, y), 0x7f);
+ }
+
+ oldX = x;
+ oldY = y;
+ }
+}
+
+void Graphics_v1::drawCornerPixel(Common::Point &p, byte color, byte bits, byte quadrant) const {
+ if (bits & 4)
+ _display.putPixel(p, color);
+
+ bits += quadrant;
+
+ if (bits & 1)
+ p.x += (bits & 2 ? -1 : 1);
+ else
+ p.y += (bits & 2 ? 1 : -1);
+}
+
+void Graphics_v1::drawCorners(Common::ReadStream &corners, const Common::Point &pos, byte rotation, byte scaling, byte color) const {
+ const byte stepping[] = {
+ 0xff, 0xfe, 0xfa, 0xf4, 0xec, 0xe1, 0xd4, 0xc5,
+ 0xb4, 0xa1, 0x8d, 0x78, 0x61, 0x49, 0x31, 0x18,
+ 0xff
+ };
+
+ byte quadrant = rotation >> 4;
+ rotation &= 0xf;
+ byte xStep = stepping[rotation];
+ byte yStep = stepping[(rotation ^ 0xf) + 1] + 1;
+
+ Common::Point p(pos);
+
+ while (true) {
+ byte b = corners.readByte();
+
+ if (corners.eos() || corners.err())
+ error("Error reading corners");
+
+ if (b == 0)
+ return;
+
+ do {
+ byte xFrac = 0x80;
+ byte yFrac = 0x80;
+ for (uint j = 0; j < scaling; ++j) {
+ if (xFrac + xStep + 1 > 255)
+ drawCornerPixel(p, color, b, quadrant);
+ xFrac += xStep + 1;
+ if (yFrac + yStep > 255)
+ drawCornerPixel(p, color, b, quadrant + 1);
+ yFrac += yStep;
+ }
+ b >>= 3;
+ } while (b != 0);
+ }
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/graphics_v2.cpp b/engines/adl/graphics_v2.cpp
new file mode 100644
index 0000000000..40936f5b7d
--- /dev/null
+++ b/engines/adl/graphics_v2.cpp
@@ -0,0 +1,304 @@
+/* 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.
+ *
+ */
+
+#include "common/stream.h"
+#include "common/rect.h"
+#include "common/textconsole.h"
+
+#include "adl/display.h"
+#include "adl/graphics.h"
+#include "adl/adl.h"
+
+namespace Adl {
+
+// FIXME: Add clipping
+
+#define NUM_PATTERNS 22
+#define PATTERN_LEN 4
+static const byte fillPatterns[NUM_PATTERNS][PATTERN_LEN] = {
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x80, 0x80, 0x80, 0x80 },
+ { 0xff, 0xff, 0xff, 0xff },
+ { 0x7f, 0x7f, 0x7f, 0x7f },
+ { 0x2a, 0x55, 0x2a, 0x55 },
+ { 0xaa, 0xd5, 0xaa, 0xd5 },
+ { 0x55, 0x2a, 0x55, 0x2a },
+ { 0xd5, 0xaa, 0xd5, 0xaa },
+ { 0x33, 0x66, 0x4c, 0x19 },
+ { 0xb3, 0xe6, 0xcc, 0x99 },
+ { 0x22, 0x44, 0x08, 0x11 },
+ { 0xa2, 0xc4, 0x88, 0x91 },
+ { 0x11, 0x22, 0x44, 0x08 },
+ { 0x91, 0xa2, 0xc4, 0x88 },
+ { 0x6e, 0x5d, 0x3b, 0x77 },
+ { 0xee, 0xdd, 0xbb, 0xf7 },
+ { 0x5d, 0x3b, 0x77, 0x6e },
+ { 0xdd, 0xbb, 0xf7, 0xee },
+ { 0x66, 0x4c, 0x19, 0x33 },
+ { 0xe6, 0xcc, 0x99, 0xb3 },
+ { 0x33, 0x66, 0x4c, 0x19 },
+ { 0xb3, 0xe6, 0xcc, 0x99 }
+};
+
+#define MIN_COMMAND 0xe0
+
+#define CHECK_COMMAND(X) \
+ do { \
+ if ((X) >= MIN_COMMAND) { \
+ pic.seek(-1, SEEK_CUR); \
+ return; \
+ } \
+ } while (0)
+
+#define READ_BYTE(b) \
+ do { \
+ b = pic.readByte(); \
+ if (pic.eos() || pic.err()) \
+ error("Error reading picture"); \
+ CHECK_COMMAND(b); \
+ } while (0)
+
+#define READ_POINT(p) \
+ do { \
+ READ_BYTE(p.x); \
+ p.x += _offset.x; \
+ p.x <<= 1; \
+ READ_BYTE(p.y); \
+ p.y += _offset.y; \
+ } while (0)
+
+void Graphics_v2::clear() {
+ _display.clear(0xff);
+ _color = 0;
+}
+
+void Graphics_v2::drawCorners(Common::SeekableReadStream &pic, bool yFirst) {
+ Common::Point p;
+
+ READ_POINT(p);
+
+ if (yFirst)
+ goto doYStep;
+
+ while (true) {
+ int16 n;
+
+ READ_BYTE(n);
+ n += _offset.x;
+
+ _display.putPixel(p, _color);
+
+ n <<= 1;
+ drawLine(p, Common::Point(n, p.y), _color);
+ p.x = n;
+
+doYStep:
+ READ_BYTE(n);
+ n += _offset.y;
+
+ _display.putPixel(p, _color);
+ drawLine(p, Common::Point(p.x, n), _color);
+
+ _display.putPixel(Common::Point(p.x + 1, p.y), _color);
+ drawLine(Common::Point(p.x + 1, p.y), Common::Point(p.x + 1, n), _color);
+
+ p.y = n;
+ }
+}
+
+void Graphics_v2::drawRelativeLines(Common::SeekableReadStream &pic) {
+ Common::Point p1;
+
+ READ_POINT(p1);
+ _display.putPixel(p1, _color);
+
+ while (true) {
+ Common::Point p2(p1);
+
+ byte n;
+ READ_BYTE(n);
+
+ byte h = (n & 0x70) >> 4;
+ byte l = n & 7;
+
+ if (n & 0x80)
+ p2.x -= (h << 1);
+ else
+ p2.x += (h << 1);
+
+ if (n & 8)
+ p2.y -= l;
+ else
+ p2.y += l;
+
+ drawLine(p1, p2, _color);
+ p1 = p2;
+ }
+}
+
+void Graphics_v2::drawAbsoluteLines(Common::SeekableReadStream &pic) {
+ Common::Point p1;
+
+ READ_POINT(p1);
+ _display.putPixel(p1, _color);
+
+ while (true) {
+ Common::Point p2;
+
+ READ_POINT(p2);
+ drawLine(p1, p2, _color);
+ p1 = p2;
+ }
+}
+
+static byte getPatternColor(const Common::Point &p, byte pattern) {
+ if (pattern >= NUM_PATTERNS)
+ error("Invalid fill pattern %i encountered in picture", pattern);
+
+ byte offset = (p.y & 1) << 1;
+ offset += (p.x / 7) & 3;
+
+ return fillPatterns[pattern][offset % PATTERN_LEN];
+}
+
+void Graphics_v2::fillRow(const Common::Point &p, bool stopBit, byte pattern) {
+ const byte color = getPatternColor(p, pattern);
+ _display.setPixelPalette(p, color);
+ _display.setPixelBit(p, color);
+
+ Common::Point q(p);
+ byte c = color;
+
+ while (++q.x < DISPLAY_WIDTH) {
+ if ((q.x % 7) == 0) {
+ c = getPatternColor(q, pattern);
+ // Palette is set before the first bit is tested
+ _display.setPixelPalette(q, c);
+ }
+ if (_display.getPixelBit(q) == stopBit)
+ break;
+ _display.setPixelBit(q, c);
+ }
+
+ q = p;
+ c = color;
+ while (--q.x >= 0) {
+ if ((q.x % 7) == 6) {
+ c = getPatternColor(q, pattern);
+ _display.setPixelPalette(q, c);
+ }
+ if (_display.getPixelBit(q) == stopBit)
+ break;
+ _display.setPixelBit(q, c);
+ }
+}
+
+// Basic flood fill
+void Graphics_v2::fill(Common::SeekableReadStream &pic) {
+ byte pattern;
+ READ_BYTE(pattern);
+
+ while (true) {
+ Common::Point p;
+ READ_POINT(p);
+
+ bool stopBit = !_display.getPixelBit(p);
+
+ while (--p.y >= 0) {
+ if (_display.getPixelBit(p) == stopBit)
+ break;
+ if (_display.getPixelBit(Common::Point(p.x + 1, p.y)) == stopBit)
+ break;
+ }
+
+ while (++p.y < DISPLAY_HEIGHT) {
+ if (_display.getPixelBit(p) == stopBit)
+ break;
+ if (_display.getPixelBit(Common::Point(p.x + 1, p.y)) == stopBit)
+ break;
+ fillRow(p, stopBit, pattern);
+ }
+ }
+}
+
+void Graphics_v2::drawPic(Common::SeekableReadStream &pic, const Common::Point &pos) {
+ _color = 0;
+ _offset = pos;
+
+ while (true) {
+ byte opcode = pic.readByte();
+
+ if (pic.eos() || pic.err())
+ error("Error reading picture");
+
+ switch (opcode) {
+ case 0xe0:
+ drawCorners(pic, false);
+ break;
+ case 0xe1:
+ drawCorners(pic, true);
+ break;
+ case 0xe2:
+ drawRelativeLines(pic);
+ break;
+ case 0xe3:
+ drawAbsoluteLines(pic);
+ break;
+ case 0xe4:
+ fill(pic);
+ break;
+ case 0xe5:
+ clear();
+ break;
+ case 0xf0:
+ _color = 0x00;
+ break;
+ case 0xf1:
+ _color = 0x2a;
+ break;
+ case 0xf2:
+ _color = 0x55;
+ break;
+ case 0xf3:
+ _color = 0x7f;
+ break;
+ case 0xf4:
+ _color = 0x80;
+ break;
+ case 0xf5:
+ _color = 0xaa;
+ break;
+ case 0xf6:
+ _color = 0xd5;
+ break;
+ case 0xf7:
+ _color = 0xff;
+ break;
+ case 0xff:
+ return;
+ default:
+ error("Invalid pic opcode %02x", opcode);
+ }
+ }
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
new file mode 100644
index 0000000000..096d8ef496
--- /dev/null
+++ b/engines/adl/hires1.cpp
@@ -0,0 +1,374 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/error.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/ptr.h"
+
+#include "adl/hires1.h"
+#include "adl/display.h"
+
+namespace Adl {
+
+void HiRes1Engine::runIntro() const {
+ StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_0));
+
+ stream->seek(IDI_HR1_OFS_LOGO_0);
+ _display->setMode(DISPLAY_MODE_HIRES);
+ _display->loadFrameBuffer(*stream);
+ _display->updateHiResScreen();
+ delay(4000);
+
+ if (shouldQuit())
+ return;
+
+ _display->setMode(DISPLAY_MODE_TEXT);
+
+ StreamPtr basic(_files->createReadStream(IDS_HR1_LOADER));
+ Common::String str;
+
+ str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_0, '"');
+ _display->printAsciiString(str + '\r');
+
+ str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_1, '"');
+ _display->printAsciiString(str + "\r\r");
+
+ str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_2, '"');
+ _display->printAsciiString(str + "\r\r");
+
+ str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_3, '"');
+ _display->printAsciiString(str + '\r');
+
+ inputKey();
+ if (g_engine->shouldQuit())
+ return;
+
+ _display->setMode(DISPLAY_MODE_MIXED);
+
+ str = readStringAt(*stream, IDI_HR1_OFS_GAME_OR_HELP);
+
+ bool instructions = false;
+
+ while (1) {
+ _display->printString(str);
+ Common::String s = inputString();
+
+ if (g_engine->shouldQuit())
+ break;
+
+ if (s.empty())
+ continue;
+
+ if (s[0] == APPLECHAR('I')) {
+ instructions = true;
+ break;
+ } else if (s[0] == APPLECHAR('G')) {
+ break;
+ }
+ };
+
+ if (instructions) {
+ _display->setMode(DISPLAY_MODE_TEXT);
+ stream->seek(IDI_HR1_OFS_INTRO_TEXT);
+
+ const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 };
+
+ uint page = 0;
+ while (pages[page] != 0) {
+ _display->home();
+
+ uint count = pages[page++];
+ for (uint i = 0; i < count; ++i) {
+ str = readString(*stream);
+ _display->printString(str);
+ stream->seek(3, SEEK_CUR);
+ }
+
+ inputString();
+
+ if (g_engine->shouldQuit())
+ return;
+
+ stream->seek(6, SEEK_CUR);
+ }
+ }
+
+ _display->printAsciiString("\r");
+
+ _display->setMode(DISPLAY_MODE_MIXED);
+
+ // Title screen shown during loading
+ stream.reset(_files->createReadStream(IDS_HR1_EXE_1));
+ stream->seek(IDI_HR1_OFS_LOGO_1);
+ _display->loadFrameBuffer(*stream);
+ _display->updateHiResScreen();
+ delay(2000);
+}
+
+void HiRes1Engine::init() {
+ if (Common::File::exists("MYSTHOUS.DSK")) {
+ _files = new Files_DOS33();
+ if (!static_cast<Files_DOS33 *>(_files)->open("MYSTHOUS.DSK"))
+ error("Failed to open MYSTHOUS.DSK");
+ } else
+ _files = new Files_Plain();
+
+ _graphics = new Graphics_v1(*_display);
+
+ StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_1));
+
+ // Some messages have overrides inside the executable
+ _gameStrings.cantGoThere = readStringAt(*stream, IDI_HR1_OFS_STR_CANT_GO_THERE);
+ _gameStrings.dontHaveIt = readStringAt(*stream, IDI_HR1_OFS_STR_DONT_HAVE_IT);
+ _gameStrings.dontUnderstand = readStringAt(*stream, IDI_HR1_OFS_STR_DONT_UNDERSTAND);
+ _gameStrings.gettingDark = readStringAt(*stream, IDI_HR1_OFS_STR_GETTING_DARK);
+
+ // Load other strings from executable
+ _strings.enterCommand = readStringAt(*stream, IDI_HR1_OFS_STR_ENTER_COMMAND);
+ _strings.verbError = readStringAt(*stream, IDI_HR1_OFS_STR_VERB_ERROR);
+ _strings.nounError = readStringAt(*stream, IDI_HR1_OFS_STR_NOUN_ERROR);
+ _strings.playAgain = readStringAt(*stream, IDI_HR1_OFS_STR_PLAY_AGAIN);
+ _strings.pressReturn = readStringAt(*stream, IDI_HR1_OFS_STR_PRESS_RETURN);
+ _strings.lineFeeds = readStringAt(*stream, IDI_HR1_OFS_STR_LINE_FEEDS);
+
+ // Set message IDs
+ _messageIds.cantGoThere = IDI_HR1_MSG_CANT_GO_THERE;
+ _messageIds.dontUnderstand = IDI_HR1_MSG_DONT_UNDERSTAND;
+ _messageIds.itemDoesntMove = IDI_HR1_MSG_ITEM_DOESNT_MOVE;
+ _messageIds.itemNotHere = IDI_HR1_MSG_ITEM_NOT_HERE;
+ _messageIds.thanksForPlaying = IDI_HR1_MSG_THANKS_FOR_PLAYING;
+
+ // Load message offsets
+ stream->seek(IDI_HR1_OFS_MSGS);
+ for (uint i = 0; i < IDI_HR1_NUM_MESSAGES; ++i)
+ _messages.push_back(_files->getDataBlock(IDS_HR1_MESSAGES, stream->readUint16LE()));
+
+ // Load picture data from executable
+ stream->seek(IDI_HR1_OFS_PICS);
+ for (uint i = 1; i <= IDI_HR1_NUM_PICS; ++i) {
+ byte block = stream->readByte();
+ Common::String name = Common::String::format("BLOCK%i", block);
+ uint16 offset = stream->readUint16LE();
+ _pictures[i] = _files->getDataBlock(name, offset);
+ }
+
+ // Load commands from executable
+ stream->seek(IDI_HR1_OFS_CMDS_1);
+ readCommands(*stream, _roomCommands);
+
+ stream->seek(IDI_HR1_OFS_CMDS_0);
+ readCommands(*stream, _globalCommands);
+
+ // Load dropped item offsets
+ stream->seek(IDI_HR1_OFS_ITEM_OFFSETS);
+ for (uint i = 0; i < IDI_HR1_NUM_ITEM_OFFSETS; ++i) {
+ Common::Point p;
+ p.x = stream->readByte();
+ p.y = stream->readByte();
+ _itemOffsets.push_back(p);
+ }
+
+ // Load right-angle line art
+ stream->seek(IDI_HR1_OFS_CORNERS);
+ uint16 cornersCount = stream->readUint16LE();
+ for (uint i = 0; i < cornersCount; ++i)
+ _corners.push_back(_files->getDataBlock(IDS_HR1_EXE_1, IDI_HR1_OFS_CORNERS + stream->readUint16LE()));
+
+ if (stream->eos() || stream->err())
+ error("Failed to read game data from '" IDS_HR1_EXE_1 "'");
+
+ stream->seek(IDI_HR1_OFS_VERBS);
+ loadWords(*stream, _verbs, _priVerbs);
+
+ stream->seek(IDI_HR1_OFS_NOUNS);
+ loadWords(*stream, _nouns, _priNouns);
+}
+
+void HiRes1Engine::initGameState() {
+ _state.vars.resize(IDI_HR1_NUM_VARS);
+
+ StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_1));
+
+ // Load room data from executable
+ _roomDesc.clear();
+ stream->seek(IDI_HR1_OFS_ROOMS);
+ for (uint i = 0; i < IDI_HR1_NUM_ROOMS; ++i) {
+ Room room;
+ stream->readByte();
+ _roomDesc.push_back(stream->readByte());
+ for (uint j = 0; j < 6; ++j)
+ room.connections[j] = stream->readByte();
+ room.picture = stream->readByte();
+ room.curPicture = stream->readByte();
+ _state.rooms.push_back(room);
+ }
+
+ // Load item data from executable
+ stream->seek(IDI_HR1_OFS_ITEMS);
+ byte id;
+ while ((id = stream->readByte()) != 0xff) {
+ Item item = Item();
+ item.id = id;
+ item.noun = stream->readByte();
+ item.room = stream->readByte();
+ item.picture = stream->readByte();
+ item.isLineArt = stream->readByte();
+ item.position.x = stream->readByte();
+ item.position.y = stream->readByte();
+ item.state = stream->readByte();
+ item.description = stream->readByte();
+
+ stream->readByte();
+
+ byte size = stream->readByte();
+
+ for (uint i = 0; i < size; ++i)
+ item.roomPictures.push_back(stream->readByte());
+
+ _state.items.push_back(item);
+ }
+}
+
+void HiRes1Engine::restartGame() {
+ _display->printString(_strings.pressReturn);
+ initState();
+ _display->printAsciiString(_strings.lineFeeds);
+}
+
+void HiRes1Engine::printString(const Common::String &str) {
+ Common::String wrap = str;
+ wordWrap(wrap);
+ _display->printString(wrap);
+
+ if (_messageDelay)
+ delay(14 * 166018 / 1000);
+}
+
+Common::String HiRes1Engine::loadMessage(uint idx) const {
+ StreamPtr stream(_messages[idx]->createReadStream());
+ return readString(*stream, APPLECHAR('\r')) + APPLECHAR('\r');
+}
+
+void HiRes1Engine::printMessage(uint idx) {
+ // Messages with hardcoded overrides don't delay after printing.
+ // It's unclear if this is a bug or not. In some cases the result
+ // is that these strings will scroll past the four-line text window
+ // before the user gets a chance to read them.
+ // NOTE: later games seem to wait for a key when the text window
+ // overflows and don't use delays. It might be better to use
+ // that system for this game as well.
+ switch (idx) {
+ case IDI_HR1_MSG_CANT_GO_THERE:
+ _display->printString(_gameStrings.cantGoThere);
+ return;
+ case IDI_HR1_MSG_DONT_HAVE_IT:
+ _display->printString(_gameStrings.dontHaveIt);
+ return;
+ case IDI_HR1_MSG_DONT_UNDERSTAND:
+ _display->printString(_gameStrings.dontUnderstand);
+ return;
+ case IDI_HR1_MSG_GETTING_DARK:
+ _display->printString(_gameStrings.gettingDark);
+ return;
+ default:
+ printString(loadMessage(idx));
+ }
+}
+
+void HiRes1Engine::drawItems() {
+ Common::List<Item>::iterator item;
+
+ uint dropped = 0;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
+ // Skip items not in this room
+ if (item->room != _state.room)
+ continue;
+
+ if (item->state == IDI_ITEM_DROPPED) {
+ // Draw dropped item if in normal view
+ if (getCurRoom().picture == getCurRoom().curPicture)
+ drawItem(*item, _itemOffsets[dropped++]);
+ } else {
+ // Draw fixed item if current view is in the pic list
+ Common::Array<byte>::const_iterator pic;
+
+ for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) {
+ if (*pic == getCurRoom().curPicture) {
+ drawItem(*item, item->position);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void HiRes1Engine::drawItem(Item &item, const Common::Point &pos) {
+ if (item.isLineArt) {
+ StreamPtr stream(_corners[item.picture - 1]->createReadStream());
+ static_cast<Graphics_v1 *>(_graphics)->drawCorners(*stream, pos);
+ } else
+ drawPic(item.picture, pos);
+}
+
+void HiRes1Engine::loadRoom(byte roomNr) {
+ _roomData.description = loadMessage(_roomDesc[_state.room - 1]);
+}
+
+void HiRes1Engine::showRoom() {
+ clearScreen();
+ loadRoom(_state.room);
+
+ if (!_state.isDark) {
+ drawPic(getCurRoom().curPicture);
+ drawItems();
+ }
+
+ _display->updateHiResScreen();
+ _messageDelay = false;
+ printString(_roomData.description);
+ _messageDelay = true;
+}
+
+void HiRes1Engine::wordWrap(Common::String &str) const {
+ uint end = 39;
+
+ while (1) {
+ if (str.size() <= end)
+ return;
+
+ while (str[end] != APPLECHAR(' '))
+ --end;
+
+ str.setChar(APPLECHAR('\r'), end);
+ end += 40;
+ }
+}
+
+Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd) {
+ return new HiRes1Engine(syst, gd);
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h
new file mode 100644
index 0000000000..c060bc892e
--- /dev/null
+++ b/engines/adl/hires1.h
@@ -0,0 +1,134 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_HIRES1_H
+#define ADL_HIRES1_H
+
+#include "common/str.h"
+
+#include "adl/adl.h"
+#include "adl/graphics.h"
+#include "adl/disk.h"
+
+namespace Common {
+class ReadStream;
+struct Point;
+}
+
+namespace Adl {
+
+#define IDS_HR1_EXE_0 "AUTO LOAD OBJ"
+#define IDS_HR1_EXE_1 "ADVENTURE"
+#define IDS_HR1_LOADER "MYSTERY.HELLO"
+#define IDS_HR1_MESSAGES "MESSAGES"
+
+#define IDI_HR1_NUM_ROOMS 41
+#define IDI_HR1_NUM_PICS 97
+#define IDI_HR1_NUM_VARS 20
+#define IDI_HR1_NUM_ITEM_OFFSETS 21
+#define IDI_HR1_NUM_MESSAGES 168
+
+// Messages used outside of scripts
+#define IDI_HR1_MSG_CANT_GO_THERE 137
+#define IDI_HR1_MSG_DONT_UNDERSTAND 37
+#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151
+#define IDI_HR1_MSG_ITEM_NOT_HERE 152
+#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140
+#define IDI_HR1_MSG_DONT_HAVE_IT 127
+#define IDI_HR1_MSG_GETTING_DARK 7
+
+#define IDI_HR1_OFS_STR_ENTER_COMMAND 0x5bbc
+#define IDI_HR1_OFS_STR_VERB_ERROR 0x5b4f
+#define IDI_HR1_OFS_STR_NOUN_ERROR 0x5b8e
+#define IDI_HR1_OFS_STR_PLAY_AGAIN 0x5f1e
+#define IDI_HR1_OFS_STR_CANT_GO_THERE 0x6c0a
+#define IDI_HR1_OFS_STR_DONT_HAVE_IT 0x6c31
+#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51
+#define IDI_HR1_OFS_STR_GETTING_DARK 0x6c7c
+#define IDI_HR1_OFS_STR_PRESS_RETURN 0x5f68
+#define IDI_HR1_OFS_STR_LINE_FEEDS 0x59d4
+
+#define IDI_HR1_OFS_PD_TEXT_0 0x005d
+#define IDI_HR1_OFS_PD_TEXT_1 0x012b
+#define IDI_HR1_OFS_PD_TEXT_2 0x016d
+#define IDI_HR1_OFS_PD_TEXT_3 0x0259
+
+#define IDI_HR1_OFS_INTRO_TEXT 0x0066
+#define IDI_HR1_OFS_GAME_OR_HELP 0x000f
+
+#define IDI_HR1_OFS_LOGO_0 0x1003
+#define IDI_HR1_OFS_LOGO_1 0x1800
+
+#define IDI_HR1_OFS_ITEMS 0x0100
+#define IDI_HR1_OFS_ROOMS 0x050a
+#define IDI_HR1_OFS_PICS 0x4b03
+#define IDI_HR1_OFS_CMDS_0 0x3c00
+#define IDI_HR1_OFS_CMDS_1 0x3d00
+#define IDI_HR1_OFS_MSGS 0x4d00
+
+#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff
+#define IDI_HR1_OFS_CORNERS 0x4f00
+
+#define IDI_HR1_OFS_VERBS 0x3800
+#define IDI_HR1_OFS_NOUNS 0x0f00
+
+class HiRes1Engine : public AdlEngine {
+public:
+ HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine(syst, gd),
+ _files(nullptr),
+ _messageDelay(true) { }
+ ~HiRes1Engine() { delete _files; }
+
+private:
+ // AdlEngine
+ void runIntro() const;
+ void init();
+ void initGameState();
+ void restartGame();
+ void printString(const Common::String &str);
+ Common::String loadMessage(uint idx) const;
+ void printMessage(uint idx);
+ void drawItems();
+ void drawItem(Item &item, const Common::Point &pos);
+ void loadRoom(byte roomNr);
+ void showRoom();
+
+ void wordWrap(Common::String &str) const;
+
+ Files *_files;
+ Common::File _exe;
+ Common::Array<DataBlockPtr> _corners;
+ Common::Array<byte> _roomDesc;
+ bool _messageDelay;
+
+ struct {
+ Common::String cantGoThere;
+ Common::String dontHaveIt;
+ Common::String dontUnderstand;
+ Common::String gettingDark;
+ } _gameStrings;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp
new file mode 100644
index 0000000000..d8e8a65e29
--- /dev/null
+++ b/engines/adl/hires2.cpp
@@ -0,0 +1,183 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/error.h"
+#include "common/file.h"
+#include "common/stream.h"
+
+#include "adl/hires2.h"
+#include "adl/display.h"
+#include "adl/graphics.h"
+#include "adl/disk.h"
+
+namespace Adl {
+
+void HiRes2Engine::runIntro() const {
+ StreamPtr stream(_disk->createReadStream(0x00, 0xd, 0x17, 1));
+
+ _display->setMode(DISPLAY_MODE_TEXT);
+
+ Common::String str = readString(*stream);
+
+ if (stream->eos() || stream->err())
+ error("Error reading disk image");
+
+ _display->printString(str);
+ delay(2000);
+}
+
+void HiRes2Engine::init() {
+ _graphics = new Graphics_v2(*_display);
+
+ _disk = new DiskImage_DSK();
+ if (!_disk->open(IDS_HR2_DISK_IMAGE))
+ error("Failed to open disk image '" IDS_HR2_DISK_IMAGE "'");
+
+ StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 4));
+
+ for (uint i = 0; i < IDI_HR2_NUM_MESSAGES; ++i)
+ _messages.push_back(readDataBlockPtr(*stream));
+
+ // Read parser messages
+ stream.reset(_disk->createReadStream(0x1a, 0x1));
+ _strings.verbError = readStringAt(*stream, 0x4f);
+ _strings.nounError = readStringAt(*stream, 0x8e);
+ _strings.enterCommand = readStringAt(*stream, 0xbc);
+
+ // Read time string
+ stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7));
+ _strings_v2.time = readString(*stream, 0xff);
+
+ // Read line feeds
+ stream.reset(_disk->createReadStream(0x19, 0xb, 0xf8, 1));
+ _strings.lineFeeds = readString(*stream);
+
+ // Read opcode strings
+ stream.reset(_disk->createReadStream(0x1a, 0x6, 0x00, 2));
+ _strings_v2.saveInsert = readStringAt(*stream, 0x5f);
+ _strings_v2.saveReplace = readStringAt(*stream, 0xe5);
+ _strings_v2.restoreInsert = readStringAt(*stream, 0x132);
+ _strings_v2.restoreReplace = readStringAt(*stream, 0x1c2);
+ _strings.playAgain = readStringAt(*stream, 0x225);
+ _strings.pressReturn = readStringAt(*stream, 0x25f);
+
+ _messageIds.cantGoThere = IDI_HR2_MSG_CANT_GO_THERE;
+ _messageIds.dontUnderstand = IDI_HR2_MSG_DONT_UNDERSTAND;
+ _messageIds.itemDoesntMove = IDI_HR2_MSG_ITEM_DOESNT_MOVE;
+ _messageIds.itemNotHere = IDI_HR2_MSG_ITEM_NOT_HERE;
+ _messageIds.thanksForPlaying = IDI_HR2_MSG_THANKS_FOR_PLAYING;
+
+ // Load global picture data
+ stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0));
+ byte picNr;
+ while ((picNr = stream->readByte()) != 0xff) {
+ if (stream->eos() || stream->err())
+ error("Error reading global pic list");
+
+ _pictures[picNr] = readDataBlockPtr(*stream);
+ }
+
+ // Load item picture data
+ stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05));
+ for (uint i = 0; i < IDI_HR2_NUM_ITEM_PICS; ++i) {
+ stream->readByte(); // number
+ _itemPics.push_back(readDataBlockPtr(*stream));
+ }
+
+ // Load commands from executable
+ stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 4));
+ readCommands(*stream, _roomCommands);
+
+ stream.reset(_disk->createReadStream(0x1f, 0x7, 0x00, 2));
+ readCommands(*stream, _globalCommands);
+
+ // Load dropped item offsets
+ stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15));
+ for (uint i = 0; i < IDI_HR2_NUM_ITEM_OFFSETS; ++i) {
+ Common::Point p;
+ p.x = stream->readByte();
+ p.y = stream->readByte();
+ _itemOffsets.push_back(p);
+ }
+
+ // Load verbs
+ stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3));
+ loadWords(*stream, _verbs, _priVerbs);
+
+ // Load nouns
+ stream.reset(_disk->createReadStream(0x22, 0x2, 0x00, 7));
+ loadWords(*stream, _nouns, _priNouns);
+}
+
+void HiRes2Engine::initGameState() {
+ _state.vars.resize(IDI_HR2_NUM_VARS);
+
+ StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 7));
+
+ for (uint i = 0; i < IDI_HR2_NUM_ROOMS; ++i) {
+ Room room;
+ stream->readByte(); // number
+ for (uint j = 0; j < 6; ++j)
+ room.connections[j] = stream->readByte();
+ room.data = readDataBlockPtr(*stream);
+ room.picture = stream->readByte();
+ room.curPicture = stream->readByte();
+ room.isFirstTime = stream->readByte();
+ _state.rooms.push_back(room);
+ }
+
+ stream.reset(_disk->createReadStream(0x21, 0x0, 0x00, 2));
+
+ byte id;
+ while ((id = stream->readByte()) != 0xff) {
+ Item item = Item();
+ item.id = id;
+ item.noun = stream->readByte();
+ item.room = stream->readByte();
+ item.picture = stream->readByte();
+ item.isLineArt = stream->readByte(); // Is this still used in this way?
+ item.position.x = stream->readByte();
+ item.position.y = stream->readByte();
+ item.state = stream->readByte();
+ item.description = stream->readByte();
+
+ stream->readByte(); // Struct size
+
+ byte picListSize = stream->readByte();
+
+ // Flag to keep track of what has been drawn on the screen
+ stream->readByte();
+
+ for (uint i = 0; i < picListSize; ++i)
+ item.roomPictures.push_back(stream->readByte());
+
+ _state.items.push_back(item);
+ }
+}
+
+Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd) {
+ return new HiRes2Engine(syst, gd);
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires2.h b/engines/adl/hires2.h
new file mode 100644
index 0000000000..50016725d6
--- /dev/null
+++ b/engines/adl/hires2.h
@@ -0,0 +1,66 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_HIRES2_H
+#define ADL_HIRES2_H
+
+#include "common/str.h"
+
+#include "adl/adl_v2.h"
+#include "adl/disk.h"
+
+namespace Common {
+class ReadStream;
+struct Point;
+}
+
+namespace Adl {
+
+#define IDS_HR2_DISK_IMAGE "WIZARD.DSK"
+
+#define IDI_HR2_NUM_ROOMS 135
+#define IDI_HR2_NUM_MESSAGES 255
+#define IDI_HR2_NUM_VARS 40
+#define IDI_HR2_NUM_ITEM_PICS 38
+#define IDI_HR2_NUM_ITEM_OFFSETS 16
+
+// Messages used outside of scripts
+#define IDI_HR2_MSG_CANT_GO_THERE 123
+#define IDI_HR2_MSG_DONT_UNDERSTAND 19
+#define IDI_HR2_MSG_ITEM_DOESNT_MOVE 242
+#define IDI_HR2_MSG_ITEM_NOT_HERE 4
+#define IDI_HR2_MSG_THANKS_FOR_PLAYING 239
+
+class HiRes2Engine : public AdlEngine_v2 {
+public:
+ HiRes2Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v2(syst, gd) { }
+
+private:
+ // AdlEngine
+ void runIntro() const;
+ void init();
+ void initGameState();
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/hires6.cpp b/engines/adl/hires6.cpp
new file mode 100644
index 0000000000..c42b4165a6
--- /dev/null
+++ b/engines/adl/hires6.cpp
@@ -0,0 +1,444 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/debug.h"
+#include "common/error.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/memstream.h"
+
+#include "adl/hires6.h"
+#include "adl/display.h"
+#include "adl/graphics.h"
+#include "adl/disk.h"
+
+namespace Adl {
+
+static const char *disks[] = { "DARK1A.DSK", "DARK1B.NIB", "DARK2A.NIB", "DARK2B.NIB" };
+
+#define SECTORS_PER_TRACK 16
+#define BYTES_PER_SECTOR 256
+
+static Common::MemoryReadStream *loadSectors(DiskImage *disk, byte track, byte sector = SECTORS_PER_TRACK - 1, byte count = SECTORS_PER_TRACK) {
+ const int bufSize = count * BYTES_PER_SECTOR;
+ byte *const buf = (byte *)malloc(bufSize);
+ byte *p = buf;
+
+ while (count-- > 0) {
+ StreamPtr stream(disk->createReadStream(track, sector, 0, 0));
+ stream->read(p, BYTES_PER_SECTOR);
+
+ if (stream->err() || stream->eos())
+ error("Error loading from disk image");
+
+ p += BYTES_PER_SECTOR;
+ if (sector > 0)
+ --sector;
+ else {
+ ++track;
+
+ // Skip VTOC track
+ if (track == 17)
+ ++track;
+
+ sector = SECTORS_PER_TRACK - 1;
+ }
+ }
+
+ return new Common::MemoryReadStream(buf, bufSize, DisposeAfterUse::YES);
+}
+
+void HiRes6Engine::runIntro() const {
+ DiskImage_DSK *boot(new DiskImage_DSK());
+
+ if (!boot->open(disks[0]))
+ error("Failed to open disk image '%s'", disks[0]);
+
+ StreamPtr stream(loadSectors(boot, 11, 1, 96));
+
+ _display->setMode(DISPLAY_MODE_HIRES);
+ _display->loadFrameBuffer(*stream);
+ _display->updateHiResScreen();
+ delay(256 * 8609 / 1000);
+
+ _display->loadFrameBuffer(*stream);
+ _display->updateHiResScreen();
+ delay(256 * 8609 / 1000);
+
+ _display->loadFrameBuffer(*stream);
+
+ delete boot;
+
+ // Load copyright string from boot file
+ Files_DOS33 *files(new Files_DOS33());
+
+ if (!files->open(disks[0]))
+ error("Failed to open disk image '%s'", disks[0]);
+
+ stream.reset(files->createReadStream("\010\010\010\010\010\010"));
+ Common::String copyright(readStringAt(*stream, 0x103, APPLECHAR('\r')));
+
+ delete files;
+
+ _display->updateHiResScreen();
+ _display->home();
+ _display->setMode(DISPLAY_MODE_MIXED);
+ _display->moveCursorTo(Common::Point(0, 21));
+ _display->printString(copyright);
+ delay(256 * 8609 / 1000);
+}
+
+void HiRes6Engine::init() {
+ _boot = new DiskImage_DSK();
+ _graphics = new Graphics_v2(*_display);
+
+ if (!_boot->open(disks[0]))
+ error("Failed to open disk image '%s'", disks[0]);
+
+ StreamPtr stream(loadSectors(_boot, 0x7));
+
+ // Read parser messages
+ _strings.verbError = readStringAt(*stream, 0x666);
+ _strings.nounError = readStringAt(*stream, 0x6bd);
+ _strings.enterCommand = readStringAt(*stream, 0x6e9);
+
+ // Read line feeds
+ _strings.lineFeeds = readStringAt(*stream, 0x408);
+
+ // Read opcode strings (TODO)
+ _strings_v2.saveInsert = readStringAt(*stream, 0xad8);
+ readStringAt(*stream, 0xb95); // Confirm save
+ // _strings_v2.saveReplace
+ _strings_v2.restoreInsert = readStringAt(*stream, 0xc07);
+ // _strings_v2.restoreReplace
+ _strings.playAgain = readStringAt(*stream, 0xcdf, 0xff);
+
+ _messageIds.cantGoThere = IDI_HR6_MSG_CANT_GO_THERE;
+ _messageIds.dontUnderstand = IDI_HR6_MSG_DONT_UNDERSTAND;
+ _messageIds.itemDoesntMove = IDI_HR6_MSG_ITEM_DOESNT_MOVE;
+ _messageIds.itemNotHere = IDI_HR6_MSG_ITEM_NOT_HERE;
+ _messageIds.thanksForPlaying = IDI_HR6_MSG_THANKS_FOR_PLAYING;
+
+ // Item descriptions
+ stream.reset(loadSectors(_boot, 0x6, 0xb, 2));
+ stream->seek(0x34);
+ for (uint i = 0; i < IDI_HR6_NUM_ITEM_DESCS; ++i)
+ _itemDesc.push_back(readString(*stream, 0xff));
+
+ // Load dropped item offsets
+ stream.reset(_boot->createReadStream(0x8, 0x9, 0x16));
+ for (uint i = 0; i < IDI_HR6_NUM_ITEM_OFFSETS; ++i) {
+ Common::Point p;
+ p.x = stream->readByte();
+ p.y = stream->readByte();
+ _itemOffsets.push_back(p);
+ }
+
+ // Location of game data for each disc
+ stream.reset(_boot->createReadStream(0x5, 0xa, 0x03));
+ for (uint i = 0; i < sizeof(disks); ++i) {
+ DiskDataDesc desc;
+ desc.track = stream->readByte();
+ desc.sector = stream->readByte();
+ desc.offset = stream->readByte();
+ desc.volume = stream->readByte();
+ _diskDataDesc.push_back(desc);
+ }
+
+ // DataBlockPtr offsets for each disk
+ stream.reset(_boot->createReadStream(0x3, 0xf, 0x03));
+ for (uint i = 0; i < sizeof(disks); ++i) {
+ DiskOffset offset;
+ offset.track = stream->readByte();
+ offset.sector = stream->readByte();
+ _diskOffsets.push_back(offset);
+ }
+}
+
+void HiRes6Engine::loadDisk(byte disk) {
+ delete _disk;
+ _disk = new DiskImage_NIB();
+
+ if (!_disk->open(disks[disk]))
+ error("Failed to open disk image '%s'", disks[disk]);
+
+ _curDisk = 0;
+
+ // Load item picture data (indexed on boot disk)
+ StreamPtr stream(_boot->createReadStream(0xb, 0xd, 0x08));
+ _itemPics.clear();
+ for (uint i = 0; i < IDI_HR6_NUM_ITEM_PICS; ++i) {
+ stream->readByte();
+ _itemPics.push_back(readDataBlockPtr(*stream));
+ }
+
+ _curDisk = disk;
+
+ byte track = _diskDataDesc[disk].track;
+ byte sector = _diskDataDesc[disk].sector;
+ uint offset = _diskDataDesc[disk].offset;
+
+ applyDiskOffset(track, sector);
+
+ for (uint block = 0; block < 7; ++block) {
+ stream.reset(_disk->createReadStream(track, sector, offset, 1));
+
+ uint16 addr = stream->readUint16LE();
+ uint16 size = stream->readUint16LE();
+
+ stream.reset(_disk->createReadStream(track, sector, offset, size / 256 + 1));
+ stream->skip(4);
+
+ switch (addr) {
+ case 0x9000: {
+ // Messages
+ _messages.clear();
+ uint count = size / 4;
+ for (uint i = 0; i < count; ++i)
+ _messages.push_back(readDataBlockPtr(*stream));
+ break;
+ }
+ case 0x4a80: {
+ // Global pics
+ _pictures.clear();
+ byte picNr;
+ while ((picNr = stream->readByte()) != 0xff) {
+ if (stream->eos() || stream->err())
+ error("Error reading global pic list");
+ _pictures[picNr] = readDataBlockPtr(*stream);
+ }
+ break;
+ }
+ case 0x4000:
+ // Verbs
+ loadWords(*stream, _verbs, _priVerbs);
+ break;
+ case 0x1800:
+ // Nouns
+ loadWords(*stream, _nouns, _priNouns);
+ break;
+ case 0x0e00: {
+ // Rooms
+ uint count = size / 14 - 1;
+ stream->skip(14); // Skip invalid room 0
+
+ _state.rooms.clear();
+ for (uint i = 0; i < count; ++i) {
+ Room room;
+ stream->readByte(); // number
+ for (uint j = 0; j < 6; ++j)
+ room.connections[j] = stream->readByte();
+ room.data = readDataBlockPtr(*stream);
+ room.picture = stream->readByte();
+ room.curPicture = stream->readByte();
+ room.isFirstTime = stream->readByte();
+ _state.rooms.push_back(room);
+ }
+ break;
+ }
+ case 0x7b00:
+ // Global commands
+ readCommands(*stream, _globalCommands);
+ break;
+ case 0x9500:
+ // Room commands
+ readCommands(*stream, _roomCommands);
+ break;
+ default:
+ error("Unknown data block found (addr %04x; size %04x)", addr, size);
+ }
+
+ offset += 4 + size;
+ while (offset >= 256) {
+ offset -= 256;
+ ++sector;
+ if (sector >= 16) {
+ sector = 0;
+ ++track;
+ }
+ }
+ }
+}
+
+void HiRes6Engine::initGameState() {
+ _state.vars.resize(IDI_HR6_NUM_VARS);
+
+ loadDisk(1);
+
+ StreamPtr stream(_boot->createReadStream(0x3, 0xe, 0x03));
+
+ byte id;
+ while ((id = stream->readByte()) != 0xff) {
+ Item item = Item();
+ item.id = id;
+ item.noun = stream->readByte();
+ item.room = stream->readByte();
+ item.picture = stream->readByte();
+ item.isLineArt = stream->readByte(); // Now seems to be disk number
+ item.position.x = stream->readByte();
+ item.position.y = stream->readByte();
+ item.state = stream->readByte();
+ item.description = stream->readByte();
+
+ stream->readByte(); // Struct size
+
+ byte picListSize = stream->readByte();
+
+ // Flag to keep track of what has been drawn on the screen
+ stream->readByte();
+
+ for (uint i = 0; i < picListSize; ++i)
+ item.roomPictures.push_back(stream->readByte());
+
+ _state.items.push_back(item);
+ }
+
+ _currVerb = _currNoun = 0;
+}
+
+void HiRes6Engine::showRoom() {
+ bool redrawPic = false;
+
+ if (getVar(26) == 0xfe)
+ setVar(26, 0);
+ else if (getVar(26) != 0xff)
+ setVar(26, _state.room);
+
+ if (_state.room != _roomOnScreen) {
+ loadRoom(_state.room);
+
+ if (getVar(26) < 0x80 && getCurRoom().isFirstTime)
+ setVar(26, 0);
+
+ clearScreen();
+
+ if (!_state.isDark)
+ redrawPic = true;
+ } else {
+ if (getCurRoom().curPicture != _picOnScreen || _itemRemoved)
+ redrawPic = true;
+ }
+
+ if (redrawPic) {
+ _roomOnScreen = _state.room;
+ _picOnScreen = getCurRoom().curPicture;
+
+ drawPic(getCurRoom().curPicture);
+ _itemRemoved = false;
+ _itemsOnScreen = 0;
+
+ Common::List<Item>::iterator item;
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ item->isOnScreen = false;
+ }
+
+ if (!_state.isDark)
+ drawItems();
+
+ _display->updateHiResScreen();
+ setVar(2, 0xff);
+ printString(_roomData.description);
+
+ // FIXME: move to main loop?
+ _linesPrinted = 0;
+}
+
+Common::String HiRes6Engine::formatVerbError(const Common::String &verb) const {
+ Common::String err = _strings.verbError;
+
+ for (uint i = 0; i < verb.size(); ++i)
+ err.setChar(verb[i], i + 24);
+
+ err.setChar(APPLECHAR(' '), 32);
+
+ uint i = 24;
+ while (err[i] != APPLECHAR(' '))
+ ++i;
+
+ err.setChar(APPLECHAR('.'), i);
+
+ return err;
+}
+
+Common::String HiRes6Engine::formatNounError(const Common::String &verb, const Common::String &noun) const {
+ Common::String err = _strings.nounError;
+
+ for (uint i = 0; i < noun.size(); ++i)
+ err.setChar(noun[i], i + 24);
+
+ for (uint i = 35; i > 31; --i)
+ err.setChar(APPLECHAR(' '), i);
+
+ uint i = 24;
+ while (err[i] != APPLECHAR(' '))
+ ++i;
+
+ err.setChar(APPLECHAR('I'), i + 1);
+ err.setChar(APPLECHAR('S'), i + 2);
+ err.setChar(APPLECHAR('.'), i + 3);
+
+ return err;
+}
+
+void HiRes6Engine::printString(const Common::String &str) {
+ Common::String s;
+ uint found = 0;
+
+ // This does not emulate the corner cases of the original, hence this check
+ if (getVar(27) > 1)
+ error("Invalid value %i encountered for variable 27", getVar(27));
+
+ for (uint i = 0; i < str.size(); ++i) {
+ if (str[i] == '%') {
+ ++found;
+ if (found == 3)
+ found = 0;
+ } else {
+ if (found == 0 || found - 1 == getVar(27))
+ s += str[i];
+ }
+ }
+
+ if (getVar(2) != 0xff) {
+ AdlEngine_v2::printString(s);
+ } else {
+ if (getVar(26) == 0) {
+ if (str.size() != 1 || APPLECHAR(str[0]) != APPLECHAR(' '))
+ return AdlEngine_v2::printString(s);
+ setVar(2, APPLECHAR(' '));
+ } else if (getVar(26) != 0xff) {
+ setVar(2, 'P');
+ } else {
+ setVar(26, _state.room);
+ setVar(2, 1);
+ }
+
+ doAllCommands(_globalCommands, _currVerb, _currNoun);
+ }
+}
+
+Engine *HiRes6Engine_create(OSystem *syst, const AdlGameDescription *gd) {
+ return new HiRes6Engine(syst, gd);
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires6.h b/engines/adl/hires6.h
new file mode 100644
index 0000000000..4bd2bcc7cc
--- /dev/null
+++ b/engines/adl/hires6.h
@@ -0,0 +1,92 @@
+/* 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.
+ *
+ */
+
+#ifndef ADL_HIRES6_H
+#define ADL_HIRES6_H
+
+#include "common/str.h"
+
+#include "adl/adl_v3.h"
+#include "adl/disk.h"
+
+namespace Common {
+class ReadStream;
+struct Point;
+}
+
+namespace Adl {
+
+#define IDI_HR6_NUM_ROOMS 35
+#define IDI_HR6_NUM_MESSAGES 256
+#define IDI_HR6_NUM_VARS 40
+#define IDI_HR6_NUM_ITEM_DESCS 15
+#define IDI_HR6_NUM_ITEM_PICS 15
+#define IDI_HR6_NUM_ITEM_OFFSETS 16
+
+// Messages used outside of scripts
+#define IDI_HR6_MSG_CANT_GO_THERE 249
+#define IDI_HR6_MSG_DONT_UNDERSTAND 247
+#define IDI_HR6_MSG_ITEM_DOESNT_MOVE 253
+#define IDI_HR6_MSG_ITEM_NOT_HERE 254
+#define IDI_HR6_MSG_THANKS_FOR_PLAYING 252
+
+struct DiskDataDesc {
+ byte track;
+ byte sector;
+ byte offset;
+ byte volume;
+};
+
+class HiRes6Engine : public AdlEngine_v3 {
+public:
+ HiRes6Engine(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v3(syst, gd),
+ _boot(nullptr),
+ _currVerb(0),
+ _currNoun(0) {
+ }
+
+ ~HiRes6Engine() { delete _boot; }
+
+private:
+ // AdlEngine
+ void runIntro() const;
+ void init();
+ void initGameState();
+ void printRoomDescription();
+ void showRoom();
+ Common::String formatVerbError(const Common::String &verb) const;
+ Common::String formatNounError(const Common::String &verb, const Common::String &noun) const;
+
+ // AdlEngine_v2
+ void printString(const Common::String &str);
+
+ void loadDisk(byte disk);
+
+ DiskImage_DSK *_boot;
+ byte _currVerb, _currNoun;
+ Common::Array<DiskDataDesc> _diskDataDesc;
+};
+
+} // End of namespace Adl
+
+#endif
diff --git a/engines/adl/module.mk b/engines/adl/module.mk
new file mode 100644
index 0000000000..7ab37efc67
--- /dev/null
+++ b/engines/adl/module.mk
@@ -0,0 +1,28 @@
+MODULE := engines/adl
+
+MODULE_OBJS := \
+ adl.o \
+ adl_v2.o \
+ adl_v3.o \
+ console.o \
+ detection.o \
+ disk.o \
+ display.o \
+ graphics.o \
+ graphics_v1.o \
+ graphics_v2.o \
+ hires1.o \
+ hires2.o \
+ hires6.o \
+ speaker.o
+
+MODULE_DIRS += \
+ engines/adl
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_ADL), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/adl/speaker.cpp b/engines/adl/speaker.cpp
new file mode 100644
index 0000000000..532d361cd9
--- /dev/null
+++ b/engines/adl/speaker.cpp
@@ -0,0 +1,94 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/events.h"
+
+#include "engines/engine.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+
+#include "adl/speaker.h"
+#include "adl/adl.h"
+
+namespace Adl {
+
+// Number of times to duplicate each sample
+#define SAMPLE_DUP 4
+// Bell frequency in Hz
+#define BELL_FREQ 1000
+// Sample rate
+#define SAMPLE_RATE (BELL_FREQ * SAMPLE_DUP * 2)
+// Number of waves per 0.1 seconds (bell length)
+#define BELL_WAVE_COUNT (SAMPLE_RATE / 10 / SAMPLE_DUP / 2)
+// Length of bell in samples
+#define BELL_LEN (BELL_WAVE_COUNT * SAMPLE_DUP * 2)
+// Length of silence in samples
+#define SILENCE_LEN (SAMPLE_RATE / 80)
+
+Speaker::~Speaker() {
+ delete[] _bell;
+ delete[] _silence;
+}
+
+Speaker::Speaker() {
+ _bell = new byte[BELL_LEN];
+
+ byte *buf = _bell;
+ for (uint i = 0; i < BELL_WAVE_COUNT; ++i) {
+ for (uint j = 0; j < SAMPLE_DUP; ++j)
+ *buf++ = 0x00;
+ for (uint j = 0; j < SAMPLE_DUP; ++j)
+ *buf++ = 0xff;
+ }
+
+ _silence = new byte[SILENCE_LEN];
+
+ buf = _silence;
+ for (uint i = 0; i < SILENCE_LEN; ++i)
+ *buf++ = 0x80;
+}
+
+void Speaker::bell(uint count) {
+ Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SAMPLE_RATE, false);
+ Audio::SoundHandle handle;
+
+ stream->queueBuffer(_bell, BELL_LEN, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED);
+
+ for (uint i = 1; i < count; ++i) {
+ stream->queueBuffer(_silence, SILENCE_LEN, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED);
+ stream->queueBuffer(_bell, BELL_LEN, DisposeAfterUse::NO, Audio::FLAG_UNSIGNED);
+ }
+
+ stream->finish();
+
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &handle, stream);
+
+ while (!g_engine->shouldQuit() && g_system->getMixer()->isSoundHandleActive(handle)) {
+ Common::Event event;
+ static_cast<AdlEngine *>(g_engine)->pollEvent(event);
+ g_system->delayMillis(16);
+ }
+}
+
+} // End of namespace Adl
diff --git a/backends/graphics/opengl/extensions.h b/engines/adl/speaker.h
index 87452429e2..31aaac32d2 100644
--- a/backends/graphics/opengl/extensions.h
+++ b/engines/adl/speaker.h
@@ -20,22 +20,30 @@
*
*/
-#ifndef BACKENDS_GRAPHICS_OPENGL_EXTENSIONS_H
-#define BACKENDS_GRAPHICS_OPENGL_EXTENSIONS_H
+#ifndef ADL_SPEAKER_H
+#define ADL_SPEAKER_H
-namespace OpenGL {
+#include "common/types.h"
-/**
- * Checks for availability of extensions we want to use and initializes them
- * when available.
- */
-void initializeGLExtensions();
+#include "audio/mixer.h"
-/**
- * Whether non power of two textures are supported
- */
-extern bool g_extNPOTSupported;
+namespace Audio {
+class AudioStream;
+}
+
+namespace Adl {
+
+class Speaker {
+public:
+ Speaker();
+ ~Speaker();
+
+ void bell(uint count);
+
+private:
+ byte *_bell, *_silence;
+};
-} // End of namespace OpenGL
+} // End of namespace Adl
#endif
diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp
index 72629a833e..7a09f662d1 100644
--- a/engines/advancedDetector.cpp
+++ b/engines/advancedDetector.cpp
@@ -41,8 +41,8 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa
title = g.extra;
extra = "";
} else {
- while (sg->gameid) {
- if (!scumm_stricmp(g.gameid, sg->gameid))
+ while (sg->gameId) {
+ if (!scumm_stricmp(g.gameId, sg->gameId))
title = sg->description;
sg++;
}
@@ -56,7 +56,7 @@ static GameDescriptor toGameDescriptor(const ADGameDescription &g, const PlainGa
else if (g.flags & ADGF_TESTING)
gsl = kTestingGame;
- GameDescriptor gd(g.gameid, title, g.language, g.platform, 0, gsl);
+ GameDescriptor gd(g.gameId, title, g.language, g.platform, 0, gsl);
gd.updateDesc(extra);
return gd;
}
@@ -89,21 +89,38 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD
return res;
}
+static Common::String sanitizeName(const char *name) {
+ Common::String res;
+
+ while (*name) {
+ if (Common::isAlnum(*name))
+ res += tolower(*name);
+ name++;
+ }
+
+ return res;
+}
+
void AdvancedMetaEngine::updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *realDesc) const {
- if (_singleid != NULL) {
+ if (_singleId != NULL) {
desc["preferredtarget"] = desc["gameid"];
- desc["gameid"] = _singleid;
+ desc["gameid"] = _singleId;
}
if (!desc.contains("preferredtarget"))
desc["preferredtarget"] = desc["gameid"];
+ if (realDesc->flags & ADGF_AUTOGENTARGET) {
+ if (*realDesc->extra)
+ desc["preferredtarget"] = sanitizeName(realDesc->extra);
+ }
+
desc["preferredtarget"] = generatePreferredTarget(desc["preferredtarget"], realDesc);
if (_flags & kADFlagUseExtraAsHint)
desc["extra"] = realDesc->extra;
- desc.setGUIOptions(realDesc->guioptions + _guioptions);
+ desc.setGUIOptions(realDesc->guiOptions + _guiOptions);
desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
if (realDesc->flags & ADGF_ADDENGLISH)
@@ -149,7 +166,7 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
// Use fallback detector if there were no matches by other means
const ADGameDescription *fallbackDesc = fallbackDetect(allFiles, fslist);
if (fallbackDesc != 0) {
- GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameids));
+ GameDescriptor desc(toGameDescriptor(*fallbackDesc, _gameIds));
updateGameDescriptor(desc, fallbackDesc);
detectedGames.push_back(desc);
}
@@ -157,7 +174,7 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
// Otherwise use the found matches
cleanupPirated(matches);
for (uint i = 0; i < matches.size(); i++) {
- GameDescriptor desc(toGameDescriptor(*matches[i], _gameids));
+ GameDescriptor desc(toGameDescriptor(*matches[i], _gameIds));
updateGameDescriptor(desc, matches[i]);
detectedGames.push_back(desc);
}
@@ -252,10 +269,10 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
if (cleanupPirated(matches))
return Common::kNoGameDataFoundError;
- if (_singleid == NULL) {
+ if (_singleId == NULL) {
// Find the first match with correct gameid.
for (uint i = 0; i < matches.size(); i++) {
- if (matches[i]->gameid == gameid) {
+ if (matches[i]->gameId == gameid) {
agdDesc = matches[i];
break;
}
@@ -270,7 +287,7 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
if (agdDesc != 0) {
// Seems we found a fallback match. But first perform a basic
// sanity check: the gameid must match.
- if (_singleid == NULL && agdDesc->gameid != gameid)
+ if (_singleId == NULL && agdDesc->gameId != gameid)
agdDesc = 0;
}
}
@@ -284,9 +301,9 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
if (agdDesc->flags & ADGF_ADDENGLISH)
lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY);
- Common::updateGameGUIOptions(agdDesc->guioptions + _guioptions, lang);
+ Common::updateGameGUIOptions(agdDesc->guiOptions + _guiOptions, lang);
- GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameids);
+ GameDescriptor gameDescriptor = toGameDescriptor(*agdDesc, _gameIds);
bool showTestingWarning = false;
@@ -407,7 +424,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// Check which files are included in some ADGameDescription *and* are present.
// Compute MD5s and file sizes for these files.
- for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize) {
+ for (descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize) {
g = (const ADGameDescription *)descPtr;
for (fileDesc = g->filesDescriptions; fileDesc->fileName; fileDesc++) {
@@ -430,7 +447,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
// MD5 based matching
uint i;
- for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameid != 0; descPtr += _descItemSize, ++i) {
+ for (i = 0, descPtr = _gameDescriptors; ((const ADGameDescription *)descPtr)->gameId != 0; descPtr += _descItemSize, ++i) {
g = (const ADGameDescription *)descPtr;
bool fileMissing = false;
@@ -487,7 +504,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
gotAnyMatchesWithAllFiles = true;
if (!fileMissing) {
- debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameid, g->extra,
+ debug(2, "Found game: %s (%s %s/%s) (%d)", g->gameId, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
if (curFilesMatched > maxFilesMatched) {
@@ -503,7 +520,7 @@ ADGameDescList AdvancedMetaEngine::detectGame(const Common::FSNode &parent, cons
}
} else {
- debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameid, g->extra,
+ debug(5, "Skipping game: %s (%s %s/%s) (%d)", g->gameId, g->extra,
getPlatformDescription(g->platform), getLanguageDescription(g->language), i);
}
}
@@ -543,7 +560,7 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &
}
if (!fileMissing) {
- debug(4, "Matched: %s", agdesc->gameid);
+ debug(4, "Matched: %s", agdesc->gameId);
if (numMatchedFiles > maxNumMatchedFiles) {
matchedDesc = agdesc;
@@ -568,27 +585,27 @@ const ADGameDescription *AdvancedMetaEngine::detectGameFilebased(const FileMap &
}
GameList AdvancedMetaEngine::getSupportedGames() const {
- if (_singleid != NULL) {
+ if (_singleId != NULL) {
GameList gl;
- const PlainGameDescriptor *g = _gameids;
- while (g->gameid) {
- if (0 == scumm_stricmp(_singleid, g->gameid)) {
- gl.push_back(GameDescriptor(g->gameid, g->description));
+ const PlainGameDescriptor *g = _gameIds;
+ while (g->gameId) {
+ if (0 == scumm_stricmp(_singleId, g->gameId)) {
+ gl.push_back(GameDescriptor(g->gameId, g->description));
return gl;
}
g++;
}
- error("Engine %s doesn't have its singleid specified in ids list", _singleid);
+ error("Engine %s doesn't have its singleid specified in ids list", _singleId);
}
- return GameList(_gameids);
+ return GameList(_gameIds);
}
-GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const {
+GameDescriptor AdvancedMetaEngine::findGame(const char *gameId) const {
// First search the list of supported gameids for a match.
- const PlainGameDescriptor *g = findPlainGameDescriptor(gameid, _gameids);
+ const PlainGameDescriptor *g = findPlainGameDescriptor(gameId, _gameIds);
if (g)
return GameDescriptor(*g);
@@ -596,14 +613,14 @@ GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const {
return GameDescriptor();
}
-AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions)
- : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameids(gameids),
+AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions)
+ : _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameIds(gameIds),
_extraGuiOptions(extraGuiOptions) {
_md5Bytes = 5000;
- _singleid = NULL;
+ _singleId = NULL;
_flags = 0;
- _guioptions = GUIO_NONE;
+ _guiOptions = GUIO_NONE;
_maxScanDepth = 1;
_directoryGlobs = NULL;
}
diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h
index ad551698f6..ab3ec22bdc 100644
--- a/engines/advancedDetector.h
+++ b/engines/advancedDetector.h
@@ -81,6 +81,7 @@ typedef Common::HashMap<Common::String, ADFileProperties, Common::IgnoreCase_Has
enum ADGameFlags {
ADGF_NO_FLAGS = 0,
+ ADGF_AUTOGENTARGET = (1 << 20), // automatically generate gameid from extra
ADGF_UNSTABLE = (1 << 21), // flag to designate not yet officially-supported games that are not fit for public testing
ADGF_TESTING = (1 << 22), // flag to designate not yet officially-supported games that are fit for public testing
ADGF_PIRATED = (1 << 23), ///< flag to designate well known pirated versions with cracks
@@ -94,7 +95,7 @@ enum ADGameFlags {
};
struct ADGameDescription {
- const char *gameid;
+ const char *gameId;
const char *extra;
ADGameFileDescription filesDescriptions[14];
Common::Language language;
@@ -107,7 +108,7 @@ struct ADGameDescription {
*/
uint32 flags;
- const char *guioptions;
+ const char *guiOptions;
};
/**
@@ -191,7 +192,7 @@ protected:
* A list of all gameids (and their corresponding descriptions) supported
* by this engine.
*/
- const PlainGameDescriptor *_gameids;
+ const PlainGameDescriptor *_gameIds;
/**
* A map containing all the extra game GUI options the engine supports.
@@ -219,7 +220,7 @@ protected:
* address a more generic problem. We should find a better way to
* disambiguate gameids.
*/
- const char *_singleid;
+ const char *_singleId;
/**
* A bitmask of flags which can be used to configure the behavior
@@ -233,7 +234,7 @@ protected:
* entry in addition to per-game options. Refer to GameGUIOption
* enum for the list.
*/
- Common::String _guioptions;
+ Common::String _guiOptions;
/**
* Maximum depth of directories to look up.
@@ -251,7 +252,7 @@ protected:
const char * const *_directoryGlobs;
public:
- AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions = 0);
+ AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameIds, const ADExtraGuiOptionsMap *extraGuiOptions = 0);
/**
* Returns list of targets supported by the engine.
@@ -259,7 +260,7 @@ public:
*/
virtual GameList getSupportedGames() const;
- virtual GameDescriptor findGame(const char *gameid) const;
+ virtual GameDescriptor findGame(const char *gameId) const;
virtual GameList detectGames(const Common::FSList &fslist) const;
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 6e63cd3e71..60c8d1f3ef 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -37,7 +37,6 @@
#include "graphics/cursorman.h"
#include "audio/mididrv.h"
-#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/font.h"
@@ -404,6 +403,11 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
_lastSaveTime = 0;
+ _playTimeInSecondsAdjust = 0;
+ _lastUsedPlayTimeInCycles = 0;
+ _lastUsedPlayTimeInSeconds = 0;
+ _passedPlayTimeCycles = 0;
+
memset(_keyQueue, 0, sizeof(_keyQueue));
_console = nullptr;
@@ -419,6 +423,9 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
_inventory = nullptr;
_keyHoldMode = false;
+
+ _artificialDelayCurrentRoom = 0;
+ _artificialDelayCurrentPicture = 0;
}
void AgiEngine::initialize() {
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index b288557f57..79d05c4b1d 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef AGI_H
-#define AGI_H
+#ifndef AGI_AGI_H
+#define AGI_AGI_H
#include "common/scummsys.h"
#include "common/error.h"
@@ -43,8 +43,6 @@
#include "agi/logic.h"
#include "agi/sound.h"
-#include "gui/predictivedialog.h"
-
namespace Common {
class RandomSource;
}
@@ -993,4 +991,4 @@ private:
} // End of namespace Agi
-#endif /* AGI_H */
+#endif /* AGI_AGI_H */
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 7d5fd3d668..9f66d78d80 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -202,8 +202,8 @@ class AgiMetaEngine : public AdvancedMetaEngine {
public:
AgiMetaEngine() : AdvancedMetaEngine(Agi::gameDescriptions, sizeof(Agi::AGIGameDescription), agiGames, optionsList) {
- _singleid = "agi";
- _guioptions = GUIO1(GUIO_NOSPEECH);
+ _singleId = "agi";
+ _guiOptions = GUIO1(GUIO_NOSPEECH);
}
virtual const char *getName() const {
@@ -567,13 +567,13 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
// Override the gameid & extra values in g_fallbackDesc.desc. This only works
// until the fallback detector is called again, and while the MetaEngine instance
// is alive (as else the string storage is modified/deleted).
- g_fallbackDesc.desc.gameid = _gameid.c_str();
+ g_fallbackDesc.desc.gameId = _gameid.c_str();
g_fallbackDesc.desc.extra = _extra.c_str();
Common::String fallbackWarning;
fallbackWarning = "Your game version has been detected using fallback matching as a\n";
- fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra);
+ fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameId, g_fallbackDesc.desc.extra);
fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n";
fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n";
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 23256f27fb..6f83f02a4e 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -21,6 +21,7 @@
*/
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/graphics.h"
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index 6d3563a451..3b1b99f458 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -61,6 +61,14 @@ GfxMgr::GfxMgr(AgiBase *vm, GfxFont *font) : _vm(vm), _font(font) {
_displayWidthMulAdjust = 0; // visualPos * (2+0) = displayPos
_displayHeightMulAdjust = 0; // visualPos * (1+0) = displayPos
+
+ _pixels = 0;
+ _displayPixels = 0;
+
+ _activeScreen = NULL;
+ _gameScreen = NULL;
+ _priorityScreen = NULL;
+ _displayScreen = NULL;
}
/**
@@ -605,7 +613,7 @@ void GfxMgr::render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool c
switch (_upscaledHires) {
case DISPLAY_UPSCALED_640x400:
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
break;
default:
break;
@@ -660,7 +668,7 @@ void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool c
switch (_upscaledHires) {
case DISPLAY_UPSCALED_640x400:
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
break;
default:
break;
@@ -743,7 +751,7 @@ void GfxMgr::render_BlockHercules(int16 x, int16 y, int16 width, int16 height, b
offsetVisual += SCRIPT_WIDTH - width;
offsetDisplay += _displayScreenWidth - displayWidth;
- offsetDisplay += _displayScreenWidth;;
+ offsetDisplay += _displayScreenWidth;
remainingHeight--;
}
@@ -1178,13 +1186,17 @@ void GfxMgr::drawCharacterOnDisplay(int16 x, int16 y, const byte character, byte
#define SHAKE_HORIZONTAL_PIXELS 4
// Sierra used some EGA port trickery to do it, we have to do it by copying pixels around
+//
+// Shaking locations:
+// - Fanmade "Enclosure" right during the intro
+// - Space Quest 2 almost right at the start when getting captured (after walking into the space ship)
void GfxMgr::shakeScreen(int16 repeatCount) {
int shakeNr, shakeCount;
uint8 *blackSpace;
int16 shakeHorizontalPixels = SHAKE_HORIZONTAL_PIXELS * (2 + _displayWidthMulAdjust);
int16 shakeVerticalPixels = SHAKE_VERTICAL_PIXELS * (1 + _displayHeightMulAdjust);
- if ((blackSpace = (uint8 *)calloc(shakeVerticalPixels * _displayScreenWidth, 1)) == NULL)
+ if ((blackSpace = (uint8 *)calloc(shakeHorizontalPixels * _displayScreenWidth, 1)) == NULL)
return;
shakeCount = repeatCount * 8; // effectively 4 shakes per repeat
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 3bc45af5d4..7ed67949b5 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -21,6 +21,7 @@
*/
#include "common/events.h"
+#include "gui/predictivedialog.h"
#include "agi/agi.h"
#include "agi/graphics.h"
diff --git a/engines/agi/lzw.cpp b/engines/agi/lzw.cpp
index bf41e1f3b4..ecb69543d7 100644
--- a/engines/agi/lzw.cpp
+++ b/engines/agi/lzw.cpp
@@ -72,6 +72,7 @@ LZWDecoder::LZWDecoder() {
appendCharacter = (uint8 *)malloc(TABLE_SIZE * sizeof(uint8));
inputBitCount = 0; // Number of bits in input bit buffer
inputBitBuffer = 0L;
+ BITS = MAX_VALUE = MAX_CODE = 0;
}
LZWDecoder::~LZWDecoder() {
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index fed07ea986..8a62fce86c 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -662,7 +662,7 @@ void cmdWordToString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
uint16 stringNr = parameter[0];
uint16 wordNr = parameter[1];
- strcpy(state->strings[stringNr], state->_vm->_words->getEgoWord(wordNr));
+ Common::strlcpy(state->strings[stringNr], state->_vm->_words->getEgoWord(wordNr), MAX_STRINGLEN);
}
void cmdOpenDialogue(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
@@ -2014,7 +2014,7 @@ void cmdGetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// copy string to destination
// TODO: not sure if set all the time or only when ENTER is pressed
- strcpy(&state->_vm->_game.strings[stringDestNr][0], (char *)textMgr->_inputString);
+ Common::strlcpy(&state->_vm->_game.strings[stringDestNr][0], (char *)textMgr->_inputString, MAX_STRINGLEN);
textMgr->charPos_Pop();
@@ -2102,7 +2102,7 @@ void cmdSetString(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
// CM: to avoid crash in Groza (str = 150)
if (stringNr > MAX_STRINGS)
return;
- strcpy(state->strings[stringNr], state->_curLogic->texts[textNr]);
+ Common::strlcpy(state->strings[stringNr], state->_curLogic->texts[textNr], MAX_STRINGLEN);
}
void cmdDisplay(AgiGame *state, AgiEngine *vm, uint8 *parameter) {
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 4b215edc63..4505668fd1 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -231,8 +231,8 @@ uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
char ms2[MAX_STRINGLEN];
int j, k, l;
- strcpy(ms1, _game.strings[s1]);
- strcpy(ms2, _game.strings[s2]);
+ Common::strlcpy(ms1, _game.strings[s1], MAX_STRINGLEN);
+ Common::strlcpy(ms2, _game.strings[s2], MAX_STRINGLEN);
l = strlen(ms1);
for (k = 0, j = 0; k < l; k++) {
diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index a80e811f44..2b3bba89db 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -44,6 +44,8 @@ PictureMgr::PictureMgr(AgiBase *agi, GfxMgr *gfx) {
_minCommand = 0xf0;
_flags = 0;
_currentStep = 0;
+
+ _width = _height = 0;
}
void PictureMgr::putVirtPixel(int x, int y) {
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index bb5d3b8896..f8630db0b6 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -20,16 +20,15 @@
*
*/
-#include "common/config-manager.h"
+#include "audio/mixer.h"
+#include "audio/softsynth/pcspk.h"
+
#include "common/debug-channels.h"
#include "common/events.h"
#include "common/random.h"
-#include "common/textconsole.h"
#include "agi/preagi.h"
#include "agi/graphics.h"
-#include "agi/keyboard.h"
-#include "agi/text.h"
namespace Agi {
@@ -52,6 +51,8 @@ PreAgiEngine::PreAgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) :
memset(&_game, 0, sizeof(struct AgiGame));
memset(&_debug, 0, sizeof(struct AgiDebug));
memset(&_mouse, 0, sizeof(struct Mouse));
+
+ _speakerHandle = new Audio::SoundHandle();
}
void PreAgiEngine::initialize() {
@@ -76,7 +77,7 @@ void PreAgiEngine::initialize() {
_gfx->initVideo();
_speakerStream = new Audio::PCSpeaker(_mixer->getOutputRate());
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, _speakerHandle,
_speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
debugC(2, kDebugLevelMain, "Detect game");
@@ -91,8 +92,9 @@ void PreAgiEngine::initialize() {
}
PreAgiEngine::~PreAgiEngine() {
- _mixer->stopHandle(_speakerHandle);
+ _mixer->stopHandle(*_speakerHandle);
delete _speakerStream;
+ delete _speakerHandle;
delete _picture;
delete _gfx;
diff --git a/engines/agi/preagi.h b/engines/agi/preagi.h
index 289b5ecdb9..6950aa30cd 100644
--- a/engines/agi/preagi.h
+++ b/engines/agi/preagi.h
@@ -25,7 +25,10 @@
#include "agi/agi.h"
-#include "audio/softsynth/pcspk.h"
+namespace Audio {
+class SoundHandle;
+class PCSpeaker;
+}
namespace Agi {
@@ -108,7 +111,7 @@ private:
int _defaultColor;
Audio::PCSpeaker *_speakerStream;
- Audio::SoundHandle _speakerHandle;
+ Audio::SoundHandle *_speakerHandle;
};
} // End of namespace Agi
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index 620d5e0baf..0584aab683 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -255,7 +255,7 @@ bool MickeyEngine::checkMenu() {
return parse(menu.cmd[iSel0].data[iSel1], menu.arg[iSel0].data[iSel1]);
}
-void MickeyEngine::drawMenu(MSA_MENU menu, int sel0, int sel1) {
+void MickeyEngine::drawMenu(MSA_MENU &menu, int sel0, int sel1) {
int iWord;
int iRow;
int sel;
@@ -286,7 +286,7 @@ void MickeyEngine::drawMenu(MSA_MENU menu, int sel0, int sel1) {
_gfx->updateScreen();
}
-void MickeyEngine::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow, int x, int y) {
+void MickeyEngine::getMouseMenuSelRow(MSA_MENU &menu, int *sel0, int *sel1, int iRow, int x, int y) {
int iWord;
int *sel = 0;
@@ -313,7 +313,7 @@ void MickeyEngine::getMouseMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int i
}
}
-bool MickeyEngine::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow) {
+bool MickeyEngine::getMenuSelRow(MSA_MENU &menu, int *sel0, int *sel1, int iRow) {
Common::Event event;
int *sel = 0;
int nWords;
@@ -1205,7 +1205,7 @@ void MickeyEngine::printStory() {
clearScreen(IDA_DEFAULT);
for (iRow = 0; iRow < 25; iRow++) {
- strcpy(szLine, buffer + pBuf);
+ Common::strlcpy(szLine, buffer + pBuf, 41);
drawStr(iRow, 0, IDA_DEFAULT, szLine);
pBuf += strlen(szLine) + 1;
}
@@ -1213,7 +1213,7 @@ void MickeyEngine::printStory() {
clearScreen(IDA_DEFAULT);
for (iRow = 0; iRow < 21; iRow++) {
- strcpy(szLine, buffer + pBuf);
+ Common::strlcpy(szLine, buffer + pBuf, 41);
drawStr(iRow, 0, IDA_DEFAULT, szLine);
pBuf += strlen(szLine) + 1;
}
diff --git a/engines/agi/preagi_mickey.h b/engines/agi/preagi_mickey.h
index 81565d3982..066880d324 100644
--- a/engines/agi/preagi_mickey.h
+++ b/engines/agi/preagi_mickey.h
@@ -710,9 +710,9 @@ protected:
void printExeMsg(int);
void printDesc(int);
bool checkMenu();
- void drawMenu(MSA_MENU, int, int);
- void getMouseMenuSelRow(MSA_MENU, int *, int *, int, int, int);
- bool getMenuSelRow(MSA_MENU, int *, int *, int);
+ void drawMenu(MSA_MENU &, int, int);
+ void getMouseMenuSelRow(MSA_MENU &, int *, int *, int, int, int);
+ bool getMenuSelRow(MSA_MENU &, int *, int *, int);
void getMenuSel(char *, int *, int *);
void centerMenu(MSA_MENU *);
void patchMenu(MSA_MENU *);
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp
index 87ac7c19c6..8fb9daca5e 100644
--- a/engines/agi/preagi_winnie.cpp
+++ b/engines/agi/preagi_winnie.cpp
@@ -292,7 +292,7 @@ int WinnieEngine::parser(int pc, int index, uint8 *buffer) {
}
// extract menu string
- strcpy(szMenu, (char *)(buffer + pc));
+ Common::strlcpy(szMenu, (char *)(buffer + pc), 121);
XOR80(szMenu);
break;
default:
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index 0658609cd0..fc4aea3169 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -118,7 +118,7 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
out->writeByte(2); // was _game.state, 2 = STATE_RUNNING
- strcpy(gameIDstring, _game.id);
+ Common::strlcpy(gameIDstring, _game.id, 8);
out->write(gameIDstring, 8);
debugC(5, kDebugLevelMain | kDebugLevelSavegame, "Writing game id (%s, %s)", gameIDstring, _game.id);
@@ -689,9 +689,6 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
}
}
}
- for (i = vtEntries; i < SCREENOBJECTS_MAX; i++) {
- memset(&_game.screenObjTable[i], 0, sizeof(ScreenObjEntry));
- }
// Fix some pointers in screenObjTable
@@ -832,7 +829,7 @@ SavedGameSlotIdArray AgiEngine::getSavegameSlotIds() {
filenames = _saveFileMan->listSavefiles(_targetName + ".###");
Common::StringArray::iterator it;
- Common::StringArray::iterator end = filenames.end();;
+ Common::StringArray::iterator end = filenames.end();
// convert to lower-case, just to be sure
for (it = filenames.begin(); it != end; it++) {
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index edf17960ad..2c1eb021f9 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -29,9 +29,19 @@
#include "agi/sound_pcjr.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
namespace Agi {
+SoundGen::SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) {
+ _sampleRate = pMixer->getOutputRate();
+ _soundHandle = new Audio::SoundHandle();
+}
+
+SoundGen::~SoundGen() {
+ delete _soundHandle;
+}
+
//
// TODO: add support for variable sampling rate in the output device
//
@@ -183,6 +193,7 @@ SoundMgr::SoundMgr(AgiBase *agi, Audio::Mixer *pMixer) {
_playingSound = -1;
switch (_vm->_soundemu) {
+ default:
case SOUND_EMU_NONE:
case SOUND_EMU_AMIGA:
case SOUND_EMU_MAC:
diff --git a/engines/agi/sound.h b/engines/agi/sound.h
index 4b668e8cf2..8aa7a5d1df 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -23,7 +23,10 @@
#ifndef AGI_SOUND_H
#define AGI_SOUND_H
-#include "audio/mixer.h"
+namespace Audio {
+class Mixer;
+class SoundHandle;
+}
namespace Agi {
@@ -71,11 +74,8 @@ class SoundMgr;
class SoundGen {
public:
- SoundGen(AgiBase *vm, Audio::Mixer *pMixer) : _vm(vm), _mixer(pMixer) {
- _sampleRate = pMixer->getOutputRate();
- }
-
- virtual ~SoundGen() {}
+ SoundGen(AgiBase *vm, Audio::Mixer *pMixer);
+ virtual ~SoundGen();
virtual void play(int resnum) = 0;
virtual void stop(void) = 0;
@@ -83,7 +83,7 @@ public:
AgiBase *_vm;
Audio::Mixer *_mixer;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
uint32 _sampleRate;
};
diff --git a/engines/agi/sound_2gs.cpp b/engines/agi/sound_2gs.cpp
index b1bcee3920..4992b6516c 100644
--- a/engines/agi/sound_2gs.cpp
+++ b/engines/agi/sound_2gs.cpp
@@ -27,6 +27,7 @@
#include "common/memstream.h"
#include "common/str-array.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/sound_2gs.h"
@@ -55,11 +56,11 @@ SoundGen2GS::SoundGen2GS(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMixe
// Load instruments
_disableMidi = !loadInstruments();
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
SoundGen2GS::~SoundGen2GS() {
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
delete[] _wavetable;
delete[] _out;
}
diff --git a/engines/agi/sound_2gs.h b/engines/agi/sound_2gs.h
index a7a23f5b06..49a375cdbc 100644
--- a/engines/agi/sound_2gs.h
+++ b/engines/agi/sound_2gs.h
@@ -126,6 +126,7 @@ public:
memset(&osc, 0, sizeof(osc));
seg = 0;
a = 0;
+ velocity = 0;
}
const IIgsInstrumentHeader *curInstrument; ///< Currently used instrument
diff --git a/engines/agi/sound_midi.cpp b/engines/agi/sound_midi.cpp
index f5c48b3b21..6998df6862 100644
--- a/engines/agi/sound_midi.cpp
+++ b/engines/agi/sound_midi.cpp
@@ -46,7 +46,6 @@
#include "common/file.h"
#include "common/memstream.h"
#include "common/stream.h"
-#include "common/textconsole.h"
#include "agi/agi.h"
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index 9d556e048a..0a0c456e14 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -54,6 +54,7 @@
*
*/
+#include "audio/mixer.h"
#include "agi/agi.h"
#include "agi/sound.h"
#include "agi/sound_pcjr.h"
@@ -123,7 +124,7 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi
memset(_channel, 0, sizeof(_channel));
memset(_tchannel, 0, sizeof(_tchannel));
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
_v1data = NULL;
_v1size = 0;
@@ -132,7 +133,7 @@ SoundGenPCJr::SoundGenPCJr(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm, pMi
SoundGenPCJr::~SoundGenPCJr() {
free(_chanData);
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
}
void SoundGenPCJr::play(int resnum) {
diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp
index c8a7042ea3..3e44546688 100644
--- a/engines/agi/sound_sarien.cpp
+++ b/engines/agi/sound_sarien.cpp
@@ -21,8 +21,7 @@
*/
#include "common/random.h"
-
-#include "audio/mididrv.h"
+#include "audio/mixer.h"
#include "agi/agi.h"
@@ -75,6 +74,7 @@ SoundGenSarien::SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm,
_useChorus = true; // FIXME: Currently always true?
switch (_vm->_soundemu) {
+ default:
case SOUND_EMU_NONE:
_waveform = waveformRamp;
_env = true;
@@ -94,11 +94,11 @@ SoundGenSarien::SoundGenSarien(AgiBase *vm, Audio::Mixer *pMixer) : SoundGen(vm,
debug(0, "Initializing sound: envelopes disabled");
}
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
}
SoundGenSarien::~SoundGenSarien() {
- _mixer->stopHandle(_soundHandle);
+ _mixer->stopHandle(*_soundHandle);
free(_sndBuffer);
}
diff --git a/engines/agi/systemui.cpp b/engines/agi/systemui.cpp
index aeb1ded4a2..1f26267ad6 100644
--- a/engines/agi/systemui.cpp
+++ b/engines/agi/systemui.cpp
@@ -585,7 +585,7 @@ void SystemUI::readSavedGameSlots(bool filterNonexistant, bool withAutoSaveSlot)
slotIdArray.push_back(SYSTEMUI_SAVEDGAME_MAXIMUM_SLOTS); // so that the loop will process all slots
SavedGameSlotIdArray::iterator it;
- SavedGameSlotIdArray::iterator end = slotIdArray.end();;
+ SavedGameSlotIdArray::iterator end = slotIdArray.end();
for (it = slotIdArray.begin(); it != end; it++) {
curSlotId = *it;
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 0cacce2421..4aa42ffec3 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -39,6 +39,8 @@ TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) {
_words = words;
_gfx = gfx;
+ _systemUI = NULL;
+
memset(&_messageState, 0, sizeof(_messageState));
_textPos.row = 0;
_textPos.column = 0;
@@ -457,7 +459,7 @@ void TextMgr::drawMessageBox(const char *textPtr, int16 forcedHeight, int16 want
// Caller wants to force specified width/height? set it
if (forcedHeight)
_messageState.textSize_Height = forcedHeight;
-
+
if (forcedWidth) {
if (wantedWidth)
_messageState.textSize_Width = wantedWidth;
@@ -885,6 +887,12 @@ void TextMgr::stringEdit(int16 stringMaxLen) {
_inputStringRow = _textPos.row;
_inputStringColumn = _textPos.column;
+ if (_inputCursorChar) {
+ // Cursor character is shown, which means we are one beyond the start of the input
+ // Adjust the column for predictive input dialog
+ _inputStringColumn--;
+ }
+
// Caller can set the input string
_inputStringCursorPos = 0;
while (_inputStringCursorPos < inputStringLen) {
@@ -1201,7 +1209,7 @@ char *TextMgr::stringPrintf(const char *originalText) {
}
assert(resultString.size() < sizeof(resultPrintfBuffer));
- strcpy(resultPrintfBuffer, resultString.c_str());
+ Common::strlcpy(resultPrintfBuffer, resultString.c_str(), 2000);
return resultPrintfBuffer;
}
diff --git a/engines/agi/view.h b/engines/agi/view.h
index e59916da78..adcf7dd1b3 100644
--- a/engines/agi/view.h
+++ b/engines/agi/view.h
@@ -132,6 +132,8 @@ struct ScreenObjEntry {
uint8 wander_count;
// end of motion related variables
uint8 loop_flag;
+
+ ScreenObjEntry() { memset(this, 0, sizeof(ScreenObjEntry)); }
}; // struct vt_entry
} // End of namespace Agi
diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp
index 8952e649fd..48b170da75 100644
--- a/engines/agos/agos.cpp
+++ b/engines/agos/agos.cpp
@@ -32,6 +32,7 @@
#include "agos/intern.h"
#include "agos/agos.h"
#include "agos/midi.h"
+#include "agos/sound.h"
#include "backends/audiocd/audiocd.h"
diff --git a/engines/agos/agos.h b/engines/agos/agos.h
index b6b5e427e1..551df6e19b 100644
--- a/engines/agos/agos.h
+++ b/engines/agos/agos.h
@@ -32,8 +32,8 @@
#include "common/rect.h"
#include "common/stack.h"
#include "common/util.h"
+#include "audio/mixer.h"
-#include "agos/sound.h"
#include "agos/vga.h"
/**
@@ -77,10 +77,14 @@ uint fileReadItemID(Common::SeekableReadStream *in);
class MoviePlayer;
#endif
+class Sound;
class MidiPlayer;
struct Child;
struct SubObject;
+struct RoomState;
+struct SubRoom;
+struct SubSuperRoom;
struct Item;
struct WindowBlock;
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index 83682d567b..123e5805dd 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -57,6 +57,7 @@ MoviePlayer::MoviePlayer(AGOSEngine_Feeble *vm)
memset(baseName, 0, sizeof(baseName));
_ticks = 0;
+ _bgSoundStream = nullptr;
}
MoviePlayer::~MoviePlayer() {
diff --git a/engines/agos/configure.engine b/engines/agos/configure.engine
index 3ae1fb16f2..cd7fcf9d78 100644
--- a/engines/agos/configure.engine
+++ b/engines/agos/configure.engine
@@ -1,4 +1,4 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine agos "AGOS" yes "agos2" "AGOS 1 games"
-add_engine agos2 "AGOS 2 games" yes
+add_engine agos2 "AGOS 2 games" yes "" "" "highres"
diff --git a/engines/agos/cursor.cpp b/engines/agos/cursor.cpp
index 65fdc9ec99..19a38116cf 100644
--- a/engines/agos/cursor.cpp
+++ b/engines/agos/cursor.cpp
@@ -26,6 +26,7 @@
#include "graphics/cursorman.h"
#include "agos/agos.h"
+#include "agos/intern.h"
namespace AGOS {
diff --git a/engines/agos/debugger.cpp b/engines/agos/debugger.cpp
index 7ad742c928..365d84dd3f 100644
--- a/engines/agos/debugger.cpp
+++ b/engines/agos/debugger.cpp
@@ -25,6 +25,7 @@
#include "agos/debugger.h"
#include "agos/agos.h"
#include "agos/midi.h"
+#include "agos/sound.h"
namespace AGOS {
diff --git a/engines/agos/detection.cpp b/engines/agos/detection.cpp
index 82f8ad4bf2..2c89522089 100644
--- a/engines/agos/detection.cpp
+++ b/engines/agos/detection.cpp
@@ -94,13 +94,13 @@ using namespace AGOS;
class AgosMetaEngine : public AdvancedMetaEngine {
public:
AgosMetaEngine() : AdvancedMetaEngine(AGOS::gameDescriptions, sizeof(AGOS::AGOSGameDescription), agosGames) {
- _guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
+ _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD);
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
- virtual GameDescriptor findGame(const char *gameid) const {
- return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
+ virtual GameDescriptor findGame(const char *gameId) const {
+ return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
virtual const char *getName() const {
diff --git a/engines/agos/detection_tables.h b/engines/agos/detection_tables.h
index 793d4081cf..90e5a84829 100644
--- a/engines/agos/detection_tables.h
+++ b/engines/agos/detection_tables.h
@@ -2251,6 +2251,31 @@ static const AGOSGameDescription gameDescriptions[] = {
GF_TALKIE
},
+ // Simon the Sorcerer 2 - Russian DOS CD
+ {
+ {
+ "simon2",
+ "CD",
+
+ {
+ { "gsptr30", GAME_BASEFILE, "e26d162e573587f4601b88701292212c", 58851},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab", 18089},
+ { "simon2.gme", GAME_GMEFILE, "9c535d403966750ae98bdaf698375a38", 19687892},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6", 171},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9", 513},
+ { NULL, 0, NULL, 0}
+ },
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO0()
+ },
+
+ GType_SIMON2,
+ GID_SIMON2,
+ GF_TALKIE
+ },
+
// Simon the Sorcerer 2 - Czech Windows CD
{
{
diff --git a/engines/agos/drivers/accolade/adlib.cpp b/engines/agos/drivers/accolade/adlib.cpp
index 294be2b8a7..3a95d8f1c1 100644
--- a/engines/agos/drivers/accolade/adlib.cpp
+++ b/engines/agos/drivers/accolade/adlib.cpp
@@ -20,16 +20,13 @@
*
*/
-#include "agos/agos.h"
#include "agos/drivers/accolade/mididriver.h"
-#include "common/file.h"
-#include "common/mutex.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
+#include "audio/mididrv.h"
namespace AGOS {
diff --git a/engines/agos/drivers/accolade/driverfile.cpp b/engines/agos/drivers/accolade/driverfile.cpp
index 4ff2fd550f..1e7fd442df 100644
--- a/engines/agos/drivers/accolade/driverfile.cpp
+++ b/engines/agos/drivers/accolade/driverfile.cpp
@@ -20,7 +20,6 @@
*
*/
-#include "agos/agos.h"
#include "audio/mididrv.h"
#include "common/error.h"
#include "common/file.h"
diff --git a/engines/agos/drivers/accolade/mt32.cpp b/engines/agos/drivers/accolade/mt32.cpp
index 319e0ebf56..321b95f4ca 100644
--- a/engines/agos/drivers/accolade/mt32.cpp
+++ b/engines/agos/drivers/accolade/mt32.cpp
@@ -20,7 +20,6 @@
*
*/
-#include "agos/agos.h"
#include "agos/drivers/accolade/mididriver.h"
#include "audio/mididrv.h"
diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp
index 95bcc68234..b70ec674dd 100644
--- a/engines/agos/event.cpp
+++ b/engines/agos/event.cpp
@@ -23,6 +23,7 @@
#include "agos/agos.h"
#include "agos/animation.h"
#include "agos/debugger.h"
+#include "agos/sound.h"
#include "agos/intern.h"
#include "common/events.h"
@@ -427,7 +428,7 @@ void AGOSEngine::delay(uint amount) {
uint32 cur = start;
uint this_delay, vgaPeriod;
- _system->getAudioCDManager()->updateCD();
+ _system->getAudioCDManager()->update();
_debugger->onFrame();
@@ -538,7 +539,7 @@ void AGOSEngine::delay(uint amount) {
if (_leftButton == 1)
_leftButtonCount++;
- _system->getAudioCDManager()->updateCD();
+ _system->getAudioCDManager()->update();
_system->updateScreen();
diff --git a/engines/agos/feeble.cpp b/engines/agos/feeble.cpp
index bfd11fa8ea..91772621ad 100644
--- a/engines/agos/feeble.cpp
+++ b/engines/agos/feeble.cpp
@@ -39,6 +39,7 @@ AGOSEngine_Feeble::AGOSEngine_Feeble(OSystem *system, const AGOSGameDescription
_moviePlayer = 0;
_vgaCurSpritePriority = 0;
_mouseToggle = false;
+ _opcodesFeeble = nullptr;
}
AGOSEngine_Feeble::~AGOSEngine_Feeble() {
diff --git a/engines/agos/icons.cpp b/engines/agos/icons.cpp
index 2db2a52cbc..364fbf5f15 100644
--- a/engines/agos/icons.cpp
+++ b/engines/agos/icons.cpp
@@ -27,6 +27,7 @@
#include "graphics/surface.h"
#include "agos/agos.h"
+#include "agos/intern.h"
namespace AGOS {
diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp
index 686b1c35b2..3b57369f1e 100644
--- a/engines/agos/input.cpp
+++ b/engines/agos/input.cpp
@@ -26,6 +26,7 @@
#include "agos/intern.h"
#include "agos/agos.h"
#include "agos/midi.h"
+#include "agos/sound.h"
#include "agos/vga.h"
namespace AGOS {
diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp
index 2631f7998e..76d23905b7 100644
--- a/engines/agos/res.cpp
+++ b/engines/agos/res.cpp
@@ -31,7 +31,6 @@
#include "agos/agos.h"
#include "agos/intern.h"
-#include "agos/sound.h"
#include "common/zlib.h"
diff --git a/engines/agos/res_snd.cpp b/engines/agos/res_snd.cpp
index d04f1735d6..81d89cc4d3 100644
--- a/engines/agos/res_snd.cpp
+++ b/engines/agos/res_snd.cpp
@@ -28,6 +28,7 @@
#include "agos/intern.h"
#include "agos/agos.h"
#include "agos/midi.h"
+#include "agos/sound.h"
#include "agos/vga.h"
#include "backends/audiocd/audiocd.h"
@@ -228,7 +229,7 @@ void AGOSEngine_Simon1::playMusic(uint16 music, uint16 track) {
// Support for compressed music from the ScummVM Music Enhancement Project
_system->getAudioCDManager()->stop();
- _system->getAudioCDManager()->play(music + 1, -1, 0, 0);
+ _system->getAudioCDManager()->play(music + 1, -1, 0, 0, true);
if (_system->getAudioCDManager()->isPlaying())
return;
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
index b968ae645c..1ba0f56353 100644
--- a/engines/agos/saveload.cpp
+++ b/engines/agos/saveload.cpp
@@ -25,7 +25,6 @@
#include "common/textconsole.h"
#include "common/translation.h"
-#include "gui/about.h"
#include "gui/message.h"
#include "agos/agos.h"
@@ -495,7 +494,7 @@ void AGOSEngine_Elvira2::userGame(bool load) {
i = userGameGetKey(&b, 128);
if (b) {
- if (i <= 223) {
+ if (i <= 23) {
if (!confirmOverWrite(window)) {
listSaveGames();
continue;
diff --git a/engines/agos/script.cpp b/engines/agos/script.cpp
index 1dbb9c255a..5f4ff4e773 100644
--- a/engines/agos/script.cpp
+++ b/engines/agos/script.cpp
@@ -27,8 +27,8 @@
#include "common/system.h"
#include "common/textconsole.h"
-#include "agos/animation.h"
#include "agos/agos.h"
+#include "agos/intern.h"
#ifdef _WIN32_WCE
extern bool isSmartphone();
diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp
index a022335ebc..38b29d475e 100644
--- a/engines/agos/script_e1.cpp
+++ b/engines/agos/script_e1.cpp
@@ -22,6 +22,7 @@
#include "agos/agos.h"
+#include "agos/intern.h"
#include "agos/vga.h"
namespace AGOS {
diff --git a/engines/agos/script_e2.cpp b/engines/agos/script_e2.cpp
index 21b651ec12..d0cd015ce9 100644
--- a/engines/agos/script_e2.cpp
+++ b/engines/agos/script_e2.cpp
@@ -23,6 +23,7 @@
#include "agos/agos.h"
+#include "agos/intern.h"
namespace AGOS {
diff --git a/engines/agos/script_ff.cpp b/engines/agos/script_ff.cpp
index e4fadcf360..10c9e995d4 100644
--- a/engines/agos/script_ff.cpp
+++ b/engines/agos/script_ff.cpp
@@ -28,6 +28,8 @@
#include "agos/animation.h"
#include "agos/agos.h"
+#include "agos/intern.h"
+#include "agos/sound.h"
namespace AGOS {
diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp
index 60948db35a..653a162904 100644
--- a/engines/agos/script_pn.cpp
+++ b/engines/agos/script_pn.cpp
@@ -21,6 +21,7 @@
*/
#include "agos/agos.h"
+#include "agos/intern.h"
#include "agos/vga.h"
#include "common/endian.h"
diff --git a/engines/agos/script_s1.cpp b/engines/agos/script_s1.cpp
index ec3de9bf94..e7828609d9 100644
--- a/engines/agos/script_s1.cpp
+++ b/engines/agos/script_s1.cpp
@@ -26,6 +26,8 @@
#include "graphics/palette.h"
#include "agos/agos.h"
+#include "agos/intern.h"
+#include "agos/sound.h"
#ifdef _WIN32_WCE
extern bool isSmartphone();
diff --git a/engines/agos/script_s2.cpp b/engines/agos/script_s2.cpp
index 44552ecd8a..7b1f369d68 100644
--- a/engines/agos/script_s2.cpp
+++ b/engines/agos/script_s2.cpp
@@ -23,6 +23,7 @@
#include "agos/agos.h"
+#include "agos/intern.h"
#include "agos/midi.h"
#include "common/textconsole.h"
diff --git a/engines/agos/script_ww.cpp b/engines/agos/script_ww.cpp
index aff3229f8e..9394311001 100644
--- a/engines/agos/script_ww.cpp
+++ b/engines/agos/script_ww.cpp
@@ -23,6 +23,7 @@
#include "agos/agos.h"
+#include "agos/intern.h"
namespace AGOS {
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
index 3eb0aca04d..cc443f2f50 100644
--- a/engines/agos/string.cpp
+++ b/engines/agos/string.cpp
@@ -25,7 +25,6 @@
#include "common/file.h"
#include "common/textconsole.h"
-#include "gui/about.h"
#include "gui/message.h"
#include "agos/agos.h"
@@ -127,14 +126,14 @@ const byte *AGOSEngine::getStringPtrByID(uint16 stringId, bool upperCase) {
_awaitTwoByteToken = 0;
uncompressText(ptr);
_textBuffer[_textCount] = 0;
- strcpy((char *)dst, (const char *)_textBuffer);
+ Common::strlcpy((char *)dst, (const char *)_textBuffer, 180);
} else {
if (stringId < 0x8000) {
stringPtr = _stringTabPtr[stringId];
} else {
stringPtr = getLocalStringByID(stringId);
}
- strcpy((char *)dst, (const char *)stringPtr);
+ Common::strlcpy((char *)dst, (const char *)stringPtr, 180);
}
// WORKAROUND bug #1538873: The French version of Simon 1 and the
@@ -797,7 +796,7 @@ void AGOSEngine_Feeble::printInteractText(uint16 num, const char *string) {
if (*string2 == 0x00) {
if (w == 0xFFFF)
w = pixels;
- strcpy(convertedString2, string);
+ Common::strlcpy(convertedString2, string, 320);
break;
}
while (*string2 != ' ') {
diff --git a/engines/agos/string_pn.cpp b/engines/agos/string_pn.cpp
index 7a364f3ea9..06c8bbd98e 100644
--- a/engines/agos/string_pn.cpp
+++ b/engines/agos/string_pn.cpp
@@ -114,7 +114,7 @@ void AGOSEngine_PN::getObjectName(char *v, uint16 x) {
}
void AGOSEngine_PN::pcl(const char *s) {
- strcat(_sb, s);
+ Common::strlcat(_sb, s, 80);
if (strchr(s, '\n') == 0) {
for (char *str = _sb; *str; str++)
windowPutChar(_windowArray[_curWindow], *str);
diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp
index 1e6ecaa829..2aedfa26fa 100644
--- a/engines/agos/subroutine.cpp
+++ b/engines/agos/subroutine.cpp
@@ -26,6 +26,7 @@
#include "agos/agos.h"
#include "agos/intern.h"
+#include "agos/sound.h"
namespace AGOS {
@@ -563,7 +564,7 @@ restart:
else
_codePtr += 8;
- debugC(kDebugOpcode, "; %d", sub->id);
+ debugC(kDebugOpcode, "; %d", sub->id);
result = runScript();
if (result != 0) {
break;
diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp
index f761c3fc3f..2a675bf6e8 100644
--- a/engines/agos/vga.cpp
+++ b/engines/agos/vga.cpp
@@ -25,6 +25,7 @@
#include "agos/agos.h"
#include "agos/intern.h"
+#include "agos/sound.h"
#include "agos/vga.h"
#include "common/debug-channels.h"
diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp
index bc26058640..a26f189c43 100644
--- a/engines/agos/vga_e2.cpp
+++ b/engines/agos/vga_e2.cpp
@@ -25,6 +25,7 @@
#include "agos/agos.h"
#include "agos/intern.h"
+#include "agos/sound.h"
#include "common/endian.h"
#include "common/system.h"
diff --git a/engines/agos/vga_ff.cpp b/engines/agos/vga_ff.cpp
index 52e30699b0..c350c37413 100644
--- a/engines/agos/vga_ff.cpp
+++ b/engines/agos/vga_ff.cpp
@@ -26,6 +26,7 @@
#include "agos/agos.h"
#include "agos/intern.h"
+#include "agos/sound.h"
namespace AGOS {
diff --git a/engines/agos/vga_s1.cpp b/engines/agos/vga_s1.cpp
index c5f0f7874d..9b7e529e4b 100644
--- a/engines/agos/vga_s1.cpp
+++ b/engines/agos/vga_s1.cpp
@@ -24,6 +24,7 @@
#include "agos/agos.h"
#include "agos/intern.h"
+#include "agos/sound.h"
#include "agos/vga.h"
namespace AGOS {
diff --git a/engines/agos/vga_s2.cpp b/engines/agos/vga_s2.cpp
index 0c716d06c4..5326e0250f 100644
--- a/engines/agos/vga_s2.cpp
+++ b/engines/agos/vga_s2.cpp
@@ -23,6 +23,7 @@
#include "agos/agos.h"
#include "agos/intern.h"
#include "agos/midi.h"
+#include "agos/sound.h"
#include "graphics/surface.h"
diff --git a/engines/avalanche/animation.cpp b/engines/avalanche/animation.cpp
index 451b4a1c68..6946e448d8 100644
--- a/engines/avalanche/animation.cpp
+++ b/engines/avalanche/animation.cpp
@@ -27,6 +27,7 @@
/* TRIP5 Trippancy V - the sprite animation subsystem */
+#include "common/system.h"
#include "avalanche/avalanche.h"
#include "avalanche/animation.h"
diff --git a/engines/avalanche/avalanche.cpp b/engines/avalanche/avalanche.cpp
index 6cfe4dfdb6..8726ef784a 100644
--- a/engines/avalanche/avalanche.cpp
+++ b/engines/avalanche/avalanche.cpp
@@ -29,6 +29,7 @@
#include "common/random.h"
#include "common/savefile.h"
+#include "common/system.h"
#include "graphics/thumbnail.h"
namespace Avalanche {
diff --git a/engines/avalanche/clock.cpp b/engines/avalanche/clock.cpp
index 6d398d9921..4276e41d99 100644
--- a/engines/avalanche/clock.cpp
+++ b/engines/avalanche/clock.cpp
@@ -28,6 +28,8 @@
#include "avalanche/clock.h"
#include "avalanche/avalanche.h"
+#include "common/system.h"
+
namespace Avalanche {
Clock::Clock(AvalancheEngine *vm) {
diff --git a/engines/avalanche/configure.engine b/engines/avalanche/configure.engine
index 28d6a558db..9b913ff053 100644
--- a/engines/avalanche/configure.engine
+++ b/engines/avalanche/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine avalanche "Lord Avalot d'Argent" no
+add_engine avalanche "Lord Avalot d'Argent" no "" "" "highres"
diff --git a/engines/avalanche/detection.cpp b/engines/avalanche/detection.cpp
index 1ea72b613a..e35c5d2cac 100644
--- a/engines/avalanche/detection.cpp
+++ b/engines/avalanche/detection.cpp
@@ -40,7 +40,7 @@ uint32 AvalancheEngine::getFeatures() const {
}
const char *AvalancheEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
static const PlainGameDescriptor avalancheGames[] = {
diff --git a/engines/avalanche/dialogs.cpp b/engines/avalanche/dialogs.cpp
index f95440900b..d1a7234b03 100644
--- a/engines/avalanche/dialogs.cpp
+++ b/engines/avalanche/dialogs.cpp
@@ -30,6 +30,7 @@
#include "avalanche/avalanche.h"
#include "avalanche/dialogs.h"
+#include "common/system.h"
#include "common/random.h"
namespace Avalanche {
diff --git a/engines/avalanche/ghostroom.cpp b/engines/avalanche/ghostroom.cpp
index 047a3670c2..254bf5e174 100644
--- a/engines/avalanche/ghostroom.cpp
+++ b/engines/avalanche/ghostroom.cpp
@@ -29,6 +29,7 @@
#include "avalanche/ghostroom.h"
#include "common/random.h"
+#include "common/system.h"
namespace Avalanche {
diff --git a/engines/avalanche/graphics.cpp b/engines/avalanche/graphics.cpp
index 60c23594d3..03c9e9e3cb 100644
--- a/engines/avalanche/graphics.cpp
+++ b/engines/avalanche/graphics.cpp
@@ -28,6 +28,7 @@
#include "avalanche/avalanche.h"
#include "avalanche/graphics.h"
+#include "common/system.h"
#include "engines/util.h"
#include "graphics/palette.h"
diff --git a/engines/avalanche/highscore.cpp b/engines/avalanche/highscore.cpp
index 5f47aeb894..b977e2f33c 100644
--- a/engines/avalanche/highscore.cpp
+++ b/engines/avalanche/highscore.cpp
@@ -29,6 +29,7 @@
#include "avalanche/highscore.h"
#include "common/savefile.h"
+#include "common/system.h"
namespace Avalanche {
diff --git a/engines/avalanche/mainmenu.cpp b/engines/avalanche/mainmenu.cpp
index 543684556c..ff24b37e0d 100644
--- a/engines/avalanche/mainmenu.cpp
+++ b/engines/avalanche/mainmenu.cpp
@@ -28,6 +28,8 @@
#include "avalanche/avalanche.h"
#include "avalanche/mainmenu.h"
+#include "common/system.h"
+
namespace Avalanche {
MainMenu::MainMenu(AvalancheEngine *vm) {
diff --git a/engines/avalanche/nim.cpp b/engines/avalanche/nim.cpp
index b17af8767a..a0a1756e0a 100644
--- a/engines/avalanche/nim.cpp
+++ b/engines/avalanche/nim.cpp
@@ -28,6 +28,8 @@
#include "avalanche/avalanche.h"
#include "avalanche/nim.h"
+#include "common/system.h"
+
namespace Avalanche {
const char * const Nim::kNames[2] = {"Avalot", "Dogfood"};
diff --git a/engines/avalanche/parser.cpp b/engines/avalanche/parser.cpp
index 7c6d254099..112dce93ac 100644
--- a/engines/avalanche/parser.cpp
+++ b/engines/avalanche/parser.cpp
@@ -30,6 +30,7 @@
#include "avalanche/nim.h"
#include "gui/saveload.h"
+#include "common/system.h"
#include "common/translation.h"
namespace Avalanche {
diff --git a/engines/avalanche/shootemup.cpp b/engines/avalanche/shootemup.cpp
index e5e44ed934..7f6cf99974 100644
--- a/engines/avalanche/shootemup.cpp
+++ b/engines/avalanche/shootemup.cpp
@@ -29,6 +29,7 @@
#include "avalanche/shootemup.h"
#include "common/random.h"
+#include "common/system.h"
namespace Avalanche {
diff --git a/engines/avalanche/sound.cpp b/engines/avalanche/sound.cpp
index 0223bead48..a441121e90 100644
--- a/engines/avalanche/sound.cpp
+++ b/engines/avalanche/sound.cpp
@@ -23,7 +23,7 @@
#include "avalanche/avalanche.h"
#include "avalanche/sound.h"
-#include "audio/audiostream.h"
+#include "audio/softsynth/pcspk.h"
#include "common/config-manager.h"
namespace Avalanche {
diff --git a/engines/avalanche/sound.h b/engines/avalanche/sound.h
index a67016a206..f9775654b4 100644
--- a/engines/avalanche/sound.h
+++ b/engines/avalanche/sound.h
@@ -24,7 +24,10 @@
#define AVALANCHE_SOUND_H
#include "audio/mixer.h"
-#include "audio/softsynth/pcspk.h"
+
+namespace Audio {
+class PCSpeaker;
+}
namespace Avalanche {
diff --git a/engines/bbvs/bbvs.cpp b/engines/bbvs/bbvs.cpp
index d40d5e482f..e7b20512a2 100644
--- a/engines/bbvs/bbvs.cpp
+++ b/engines/bbvs/bbvs.cpp
@@ -34,6 +34,7 @@
#include "bbvs/minigames/minigame.h"
#include "audio/audiostream.h"
+#include "audio/decoders/aiff.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/error.h"
@@ -137,6 +138,21 @@ BbvsEngine::~BbvsEngine() {
}
void BbvsEngine::newGame() {
+ memset(_easterEggInput, 0, sizeof(_easterEggInput));
+ _gameTicks = 0;
+ _playVideoNumber = 0;
+ memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
+ memset(_gameVars, 0, sizeof(_gameVars));
+ memset(_sceneVisited, 0, sizeof(_sceneVisited));
+
+ _mouseX = 160;
+ _mouseY = 120;
+ _mouseButtons = 0;
+
+ _currVerbNum = kVerbLook;
+ _currTalkObjectIndex = -1;
+ _currSceneNum = 0;
+
_currInventoryItem = -1;
_newSceneNum = 32;
}
@@ -162,24 +178,10 @@ Common::Error BbvsEngine::run() {
_sound = new SoundMan();
allocSnapshot();
- memset(_easterEggInput, 0, sizeof(_easterEggInput));
- _gameTicks = 0;
- _playVideoNumber = 0;
- _bootSaveSlot = -1;
-
- memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
- memset(_gameVars, 0, sizeof(_gameVars));
- memset(_sceneVisited, 0, sizeof(_sceneVisited));
-
- _mouseX = 160;
- _mouseY = 120;
- _mouseButtons = 0;
+ newGame();
- _currVerbNum = kVerbLook;
- _currInventoryItem = -1;
- _currTalkObjectIndex = -1;
- _currSceneNum = 0;
+ _bootSaveSlot = -1;
_newSceneNum = 31;
if (ConfMan.hasKey("save_slot"))
diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h
index ff4afe9526..8d9550d423 100644
--- a/engines/bbvs/bbvs.h
+++ b/engines/bbvs/bbvs.h
@@ -24,7 +24,6 @@
#define BBVS_BBVS_H
#include "audio/mixer.h"
-#include "audio/decoders/aiff.h"
#include "common/array.h"
#include "common/events.h"
#include "common/file.h"
diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp
index 37b5e398df..7c0045ee73 100644
--- a/engines/bbvs/detection.cpp
+++ b/engines/bbvs/detection.cpp
@@ -69,7 +69,7 @@ static const char * const directoryGlobs[] = {
class BbvsMetaEngine : public AdvancedMetaEngine {
public:
BbvsMetaEngine() : AdvancedMetaEngine(Bbvs::gameDescriptions, sizeof(ADGameDescription), bbvsGames) {
- _singleid = "bbvs";
+ _singleId = "bbvs";
_maxScanDepth = 3;
_directoryGlobs = directoryGlobs;
}
diff --git a/engines/bbvs/dialogs.cpp b/engines/bbvs/dialogs.cpp
index c8470f8eef..64fa86e1ee 100644
--- a/engines/bbvs/dialogs.cpp
+++ b/engines/bbvs/dialogs.cpp
@@ -22,10 +22,13 @@
#include "bbvs/dialogs.h"
#include "common/events.h"
-#include "gui/gui-manager.h"
-#include "gui/ThemeEval.h"
+#include "gui/widget.h"
#include "engines/advancedDetector.h"
+namespace GUI {
+class CommandSender;
+}
+
namespace Bbvs {
struct MenuButton {
@@ -92,8 +95,8 @@ void MainMenu::init() {
}
void MainMenu::reflowLayout() {
- const int screenW = g_system->getOverlayWidth();
- const int screenH = g_system->getOverlayHeight();
+ const int screenW = _vm->_system->getOverlayWidth();
+ const int screenH = _vm->_system->getOverlayHeight();
const int buttonWidth = screenW * 70 / 320;
const int buttonHeight = screenH * 14 / 240;
diff --git a/engines/bbvs/dialogs.h b/engines/bbvs/dialogs.h
index 7db0b182b7..af1f70e9a7 100644
--- a/engines/bbvs/dialogs.h
+++ b/engines/bbvs/dialogs.h
@@ -25,7 +25,11 @@
#include "bbvs/bbvs.h"
#include "gui/dialog.h"
-#include "gui/widgets/edittext.h"
+
+namespace GUI {
+class ButtonWidget;
+class CommandSender;
+}
namespace Bbvs {
diff --git a/engines/bbvs/minigames/bbairguitar.cpp b/engines/bbvs/minigames/bbairguitar.cpp
index 04175f7290..f826667134 100644
--- a/engines/bbvs/minigames/bbairguitar.cpp
+++ b/engines/bbvs/minigames/bbairguitar.cpp
@@ -25,7 +25,6 @@
#include "common/savefile.h"
#include "common/translation.h"
-#include "gui/dialog.h"
#include "gui/message.h"
#include "gui/filebrowser-dialog.h"
diff --git a/engines/bbvs/saveload.cpp b/engines/bbvs/saveload.cpp
index e7725713fd..79afd112be 100644
--- a/engines/bbvs/saveload.cpp
+++ b/engines/bbvs/saveload.cpp
@@ -59,13 +59,13 @@ BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableRead
void BbvsEngine::savegame(const char *filename, const char *description) {
Common::OutSaveFile *out;
- if (!(out = g_system->getSavefileManager()->openForSaving(filename))) {
+ if (!(out = _system->getSavefileManager()->openForSaving(filename))) {
warning("Can't create file '%s', game not saved", filename);
return;
}
TimeDate curTime;
- g_system->getTimeAndDate(curTime);
+ _system->getTimeAndDate(curTime);
// Header start
out->writeUint32LE(BBVS_SAVEGAME_VERSION);
@@ -95,7 +95,7 @@ void BbvsEngine::savegame(const char *filename, const char *description) {
void BbvsEngine::loadgame(const char *filename) {
Common::InSaveFile *in;
- if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
+ if (!(in = _system->getSavefileManager()->openForLoading(filename))) {
warning("Can't open file '%s', game not loaded", filename);
return;
}
diff --git a/engines/bbvs/sound.cpp b/engines/bbvs/sound.cpp
index 7f9c00ad48..587868f26d 100644
--- a/engines/bbvs/sound.cpp
+++ b/engines/bbvs/sound.cpp
@@ -21,6 +21,7 @@
*/
#include "bbvs/sound.h"
+#include "audio/audiostream.h"
#include "audio/decoders/aiff.h"
#include "common/debug.h"
#include "common/file.h"
diff --git a/engines/bbvs/sound.h b/engines/bbvs/sound.h
index 4d3253c48e..a21d97b7ed 100644
--- a/engines/bbvs/sound.h
+++ b/engines/bbvs/sound.h
@@ -23,10 +23,13 @@
#ifndef BBVS_SOUND_H
#define BBVS_SOUND_H
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/array.h"
+namespace Audio {
+class RewindableAudioStream;
+}
+
namespace Bbvs {
class Sound {
diff --git a/engines/bbvs/spritemodule.cpp b/engines/bbvs/spritemodule.cpp
index f8b0d9afd5..74c71e5aeb 100644
--- a/engines/bbvs/spritemodule.cpp
+++ b/engines/bbvs/spritemodule.cpp
@@ -32,7 +32,8 @@ byte *Sprite::getRow(int y) {
}
SpriteModule::SpriteModule()
- : _spritesCount(0), _paletteStart(0), _paletteCount(0), _spriteData(0) {
+ : _spritesCount(0), _paletteStart(0), _paletteCount(0), _spriteData(0), _spriteDataSize(0),
+ _spriteTblOffs(0), _paletteOffs(0) {
}
SpriteModule::~SpriteModule() {
diff --git a/engines/bbvs/videoplayer.cpp b/engines/bbvs/videoplayer.cpp
index 1b721c434f..9bef02a3cc 100644
--- a/engines/bbvs/videoplayer.cpp
+++ b/engines/bbvs/videoplayer.cpp
@@ -73,7 +73,7 @@ void BbvsEngine::playVideo(int videoNum) {
}
Common::Event event;
- while (g_system->getEventManager()->pollEvent(event)) {
+ while (_system->getEventManager()->pollEvent(event)) {
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) ||
event.type == Common::EVENT_LBUTTONUP)
skipVideo = true;
diff --git a/engines/cge/cge.h b/engines/cge/cge.h
index c43358f252..d3f8a93c1d 100644
--- a/engines/cge/cge.h
+++ b/engines/cge/cge.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef CGE_H
-#define CGE_H
+#ifndef CGE_CGE_H
+#define CGE_CGE_H
#include "common/random.h"
#include "common/savefile.h"
diff --git a/engines/cge/detection.cpp b/engines/cge/detection.cpp
index 95705cbebc..82d27f8d54 100644
--- a/engines/cge/detection.cpp
+++ b/engines/cge/detection.cpp
@@ -115,7 +115,7 @@ static const ADExtraGuiOptionsMap optionsList[] = {
class CGEMetaEngine : public AdvancedMetaEngine {
public:
CGEMetaEngine() : AdvancedMetaEngine(CGE::gameDescriptions, sizeof(ADGameDescription), CGEGames, optionsList) {
- _singleid = "soltys";
+ _singleId = "soltys";
}
virtual const char *getName() const {
@@ -123,7 +123,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Soltys (c) 1994-1996 L.K. Avalon";
+ return "Soltys (C) 1994-1996 L.K. Avalon";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
diff --git a/engines/cge/events.cpp b/engines/cge/events.cpp
index c2f8982592..5d3d0a16a0 100644
--- a/engines/cge/events.cpp
+++ b/engines/cge/events.cpp
@@ -26,8 +26,6 @@
*/
#include "gui/saveload.h"
-#include "gui/about.h"
-#include "gui/message.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "common/translation.h"
diff --git a/engines/cge/sound.cpp b/engines/cge/sound.cpp
index 370b768bca..3af094ef06 100644
--- a/engines/cge/sound.cpp
+++ b/engines/cge/sound.cpp
@@ -30,8 +30,10 @@
#include "cge/cge_main.h"
#include "common/config-manager.h"
#include "common/memstream.h"
-#include "audio/decoders/raw.h"
#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
namespace CGE {
diff --git a/engines/cge/sound.h b/engines/cge/sound.h
index dc67f9408b..8e624ee575 100644
--- a/engines/cge/sound.h
+++ b/engines/cge/sound.h
@@ -29,15 +29,14 @@
#define CGE_SOUND_H
#include "cge/fileio.h"
-#include "audio/audiostream.h"
-#include "audio/decoders/wave.h"
-#include "audio/fmopl.h"
-#include "audio/mididrv.h"
-#include "audio/midiparser.h"
#include "audio/midiplayer.h"
#include "audio/mixer.h"
#include "common/memstream.h"
+namespace Audio {
+class RewindableAudioStream;
+}
+
namespace CGE {
class CGEEngine;
diff --git a/engines/cge2/cge2.h b/engines/cge2/cge2.h
index fbe4cb3abc..18f919b5eb 100644
--- a/engines/cge2/cge2.h
+++ b/engines/cge2/cge2.h
@@ -25,8 +25,8 @@
* Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
*/
-#ifndef CGE2_H
-#define CGE2_H
+#ifndef CGE2_CGE2_H
+#define CGE2_CGE2_H
#include "common/random.h"
#include "common/savefile.h"
@@ -335,4 +335,4 @@ public:
} // End of namespace CGE2
-#endif // CGE2_H
+#endif // CGE2_CGE2_H
diff --git a/engines/cge2/detection.cpp b/engines/cge2/detection.cpp
index 3ccfffe43f..2b84d167c7 100644
--- a/engines/cge2/detection.cpp
+++ b/engines/cge2/detection.cpp
@@ -111,7 +111,7 @@ static const ADExtraGuiOptionsMap optionsList[] = {
class CGE2MetaEngine : public AdvancedMetaEngine {
public:
CGE2MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), CGE2Games, optionsList) {
- _singleid = "sfinx";
+ _singleId = "sfinx";
}
virtual const char *getName() const {
@@ -119,7 +119,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Sfinx (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
+ return "Sfinx (C) 1994-1997 Janus B. Wisniewski and L.K. Avalon";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
diff --git a/engines/cge2/events.cpp b/engines/cge2/events.cpp
index 96cecc8e23..2dac04a0a5 100644
--- a/engines/cge2/events.cpp
+++ b/engines/cge2/events.cpp
@@ -26,8 +26,6 @@
*/
#include "gui/saveload.h"
-#include "gui/about.h"
-#include "gui/message.h"
#include "common/config-manager.h"
#include "common/events.h"
#include "common/translation.h"
diff --git a/engines/cge2/saveload.cpp b/engines/cge2/saveload.cpp
index 7735c077a6..cd0be84567 100644
--- a/engines/cge2/saveload.cpp
+++ b/engines/cge2/saveload.cpp
@@ -25,7 +25,7 @@
* Copyright (c) 1994-1997 Janus B. Wisniewski and L.K. Avalon
*/
-#include "common/config-manager.h"
+#include "common/memstream.h"
#include "common/savefile.h"
#include "common/system.h"
#include "graphics/thumbnail.h"
@@ -36,8 +36,6 @@
#include "cge2/snail.h"
#include "cge2/hero.h"
#include "cge2/text.h"
-#include "cge2/sound.h"
-#include "cge2/cge2_main.h"
namespace CGE2 {
diff --git a/engines/cge2/sound.cpp b/engines/cge2/sound.cpp
index 57ec5983e8..691414d84a 100644
--- a/engines/cge2/sound.cpp
+++ b/engines/cge2/sound.cpp
@@ -26,10 +26,11 @@
*/
#include "cge2/sound.h"
-#include "common/config-manager.h"
#include "common/memstream.h"
-#include "audio/decoders/raw.h"
#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
#include "cge2/cge2.h"
namespace CGE2 {
diff --git a/engines/cge2/sound.h b/engines/cge2/sound.h
index 02afe610a2..8c16f06e97 100644
--- a/engines/cge2/sound.h
+++ b/engines/cge2/sound.h
@@ -28,19 +28,17 @@
#ifndef CGE2_SOUND_H
#define CGE2_SOUND_H
-#include "cge2/fileio.h"
-#include "audio/audiostream.h"
-#include "audio/decoders/wave.h"
-#include "audio/fmopl.h"
-#include "audio/mididrv.h"
-#include "audio/midiparser.h"
#include "audio/midiplayer.h"
#include "audio/mixer.h"
-#include "common/memstream.h"
+
+namespace Audio {
+class RewindableAudioStream;
+}
namespace CGE2 {
class CGE2Engine;
+class EncryptedStream;
// sample info
struct SmpInfo {
diff --git a/engines/cge2/vga13h.cpp b/engines/cge2/vga13h.cpp
index 54f5c00d93..8b0d8b6c77 100644
--- a/engines/cge2/vga13h.cpp
+++ b/engines/cge2/vga13h.cpp
@@ -952,8 +952,9 @@ uint8 Vga::closest(Dac *pal, const uint8 colR, const uint8 colG, const uint8 col
}
uint8 Vga::closest(Dac *pal, Dac x) {
- int exp = (sizeof(long) * 8 - 1);
- long D = (1 << exp) - 1; // Maximum value of long.
+ long D = 0;
+ D = ~D;
+ D = (unsigned long)D >> 1; // Maximum value of long.
long R = x._r;
long G = x._g;
long B = x._b;
diff --git a/engines/cine/cine.h b/engines/cine/cine.h
index 7c0191b4d9..615e36d598 100644
--- a/engines/cine/cine.h
+++ b/engines/cine/cine.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef CINE_H
-#define CINE_H
+#ifndef CINE_CINE_H
+#define CINE_CINE_H
#include "common/scummsys.h"
diff --git a/engines/cine/detection.cpp b/engines/cine/detection.cpp
index 5e1ffadb1b..ec01e8734d 100644
--- a/engines/cine/detection.cpp
+++ b/engines/cine/detection.cpp
@@ -80,12 +80,12 @@ static const ADExtraGuiOptionsMap optionsList[] = {
class CineMetaEngine : public AdvancedMetaEngine {
public:
CineMetaEngine() : AdvancedMetaEngine(Cine::gameDescriptions, sizeof(Cine::CINEGameDescription), cineGames, optionsList) {
- _singleid = "cine";
- _guioptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD);
+ _singleId = "cine";
+ _guiOptions = GUIO2(GUIO_NOSPEECH, GAMEOPTION_ORIGINAL_SAVELOAD);
}
- virtual GameDescriptor findGame(const char *gameid) const {
- return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
+ virtual GameDescriptor findGame(const char *gameId) const {
+ return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
virtual const char *getName() const {
diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp
index e52fc464d5..19a2d8a82e 100644
--- a/engines/cine/main_loop.cpp
+++ b/engines/cine/main_loop.cpp
@@ -222,7 +222,7 @@ void manageEvents() {
mouseData.left = mouseLeft;
mouseData.right = mouseRight;
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
}
void getMouseData(uint16 param, uint16 *pButton, uint16 *pX, uint16 *pY) {
diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp
index 1f4f286694..dfd3a1f4bc 100644
--- a/engines/cine/saveload.cpp
+++ b/engines/cine/saveload.cpp
@@ -691,6 +691,11 @@ bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFor
}
if (strlen(bgName)) {
+ if (g_cine->getGameType() == GType_FW && (g_cine->getFeatures() & GF_CD)) {
+ char buffer[20];
+ removeExtention(buffer, bgName);
+ g_sound->setBgMusic(atoi(buffer + 1));
+ }
loadBg(bgName);
}
diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index 6ad38f4433..86eb709d5a 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -1858,7 +1858,9 @@ int FWScript::o1_playSample() {
if (g_cine->getGameType() == Cine::GType_OS && size == 0) {
return 0;
}
- g_sound->stopMusic();
+ // The DOS CD version of Future Wars uses CD audio for music
+ if (!(g_cine->getGameType() == Cine::GType_FW && (g_cine->getFeatures() & GF_CD)))
+ g_sound->stopMusic();
if (size == 0xFFFF) {
g_sound->playSound(channel, 0, data, 0, 0, 0, volume, 0);
} else {
diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp
index 7cab067371..a8b4c085ff 100644
--- a/engines/cine/sound.cpp
+++ b/engines/cine/sound.cpp
@@ -939,6 +939,10 @@ PCSound::PCSound(Audio::Mixer *mixer, CineEngine *vm)
}
_player = new PCSoundFxPlayer(_soundDriver);
+
+ // Ensure the CD is open
+ if (_vm->getGameType() == GType_FW && (_vm->getFeatures() & GF_CD))
+ g_system->getAudioCDManager()->open();
}
PCSound::~PCSound() {
diff --git a/engines/composer/composer.cpp b/engines/composer/composer.cpp
index f070338978..73d97e100d 100644
--- a/engines/composer/composer.cpp
+++ b/engines/composer/composer.cpp
@@ -21,13 +21,9 @@
*/
#include "common/scummsys.h"
-#include "common/config-manager.h"
#include "common/events.h"
-#include "common/file.h"
#include "common/random.h"
-#include "common/fs.h"
#include "common/keyboard.h"
-#include "common/substream.h"
#include "graphics/cursorman.h"
#include "graphics/surface.h"
@@ -35,9 +31,6 @@
#include "graphics/wincursor.h"
#include "engines/util.h"
-#include "engines/advancedDetector.h"
-
-#include "audio/audiostream.h"
#include "composer/composer.h"
#include "composer/graphics.h"
diff --git a/engines/composer/composer.h b/engines/composer/composer.h
index 47398fe36d..d1a85e975a 100644
--- a/engines/composer/composer.h
+++ b/engines/composer/composer.h
@@ -20,14 +20,15 @@
*
*/
-#ifndef COMPOSER_H
-#define COMPOSER_H
+#ifndef COMPOSER_COMPOSER_H
+#define COMPOSER_COMPOSER_H
#include "common/ini-file.h"
#include "common/random.h"
#include "common/system.h"
#include "common/debug.h"
#include "common/debug-channels.h"
+#include "common/error.h"
#include "common/textconsole.h"
#include "common/rect.h"
diff --git a/engines/composer/configure.engine b/engines/composer/configure.engine
index 71a79acb5d..17120a3a3d 100644
--- a/engines/composer/configure.engine
+++ b/engines/composer/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine composer "Magic Composer" yes
+add_engine composer "Magic Composer" yes "" "" "highres"
diff --git a/engines/composer/detection.cpp b/engines/composer/detection.cpp
index e250996371..689a72a743 100644
--- a/engines/composer/detection.cpp
+++ b/engines/composer/detection.cpp
@@ -38,7 +38,7 @@ int ComposerEngine::getGameType() const {
}
const char *ComposerEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 ComposerEngine::getFeatures() const {
@@ -253,6 +253,36 @@ static const ComposerGameDescription gameDescriptions[] = {
GType_ComposerV2
},
+ { // Provided by WindlePoons, "100% Kids Darby & Gregor" Pack. Bugreport #6825
+ {
+ "darby",
+ 0,
+ {
+ {"book.ini", 0, "285308372f7dddff2ca5a25c9192cf5c", 2545},
+ {"page99.rsc", 0, "40b4879e9ba6a34d6aa2a9d2e30c5ef7", 1286480},
+ AD_LISTEND
+ },
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_ComposerV2
+ },
+
+ { // Provided by Niv Baehr, Bugreport #6878
+ {
+ "darby",
+ 0,
+ AD_ENTRY1("page99.rsc", "183463d18c050563dcdec2d9f9670515"),
+ Common::HE_ISR,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_ComposerV2
+ },
+
{
{
"gregory",
@@ -296,6 +326,23 @@ static const ComposerGameDescription gameDescriptions[] = {
GType_ComposerV2
},
+ { // Provided by WindlePoons, "100% Kids Darby & Gregor" Pack. Bugreport #6825
+ {
+ "gregory",
+ 0,
+ {
+ {"book.ini", 0, "e54fc5c00de5f94e908a969e445af5d0", 2234},
+ {"page99.rsc", 0, "1ae6610de621a9901bf87b874fbf331f", 388644},
+ AD_LISTEND
+ },
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_ComposerV2
+ },
+
{ // Provided by sev
{
"princess",
@@ -386,7 +433,7 @@ static const char *directoryGlobs[] = {
class ComposerMetaEngine : public AdvancedMetaEngine {
public:
ComposerMetaEngine() : AdvancedMetaEngine(Composer::gameDescriptions, sizeof(Composer::ComposerGameDescription), composerGames) {
- _singleid = "composer";
+ _singleId = "composer";
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
diff --git a/engines/cruise/cell.cpp b/engines/cruise/cell.cpp
index b7cef41764..46539463b8 100644
--- a/engines/cruise/cell.cpp
+++ b/engines/cruise/cell.cpp
@@ -129,15 +129,12 @@ void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x
cellStruct *pNewElement;
cellStruct *si = pObject->next;
- cellStruct *var_2;
while (si) {
pObject = si;
si = si->next;
}
- var_2 = si;
-
pNewElement = (cellStruct *) MemAlloc(sizeof(cellStruct));
memset(pNewElement, 0, sizeof(cellStruct));
@@ -157,11 +154,7 @@ void createTextObject(cellStruct *pObject, int overlayIdx, int messageIdx, int x
pNewElement->parentOverlay = parentOvl;
pNewElement->gfxPtr = NULL;
- if (var_2) {
- cx = var_2;
- } else {
- cx = savePObject;
- }
+ cx = savePObject;
pNewElement->prev = cx->prev;
cx->prev = pNewElement;
diff --git a/engines/cruise/ctp.cpp b/engines/cruise/ctp.cpp
index 9515b552e1..4458e39e91 100644
--- a/engines/cruise/ctp.cpp
+++ b/engines/cruise/ctp.cpp
@@ -307,7 +307,7 @@ int initCt(const char *ctpName) {
MemFree(ptr);
if (ctpName != currentCtpName)
- strcpy(currentCtpName, ctpName);
+ Common::strlcpy(currentCtpName, ctpName, 40);
numberOfWalkboxes = segementSizeTable[6] / 2; // get the number of walkboxes
diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp
index 7a1258dbde..2eff82bc61 100644
--- a/engines/cruise/dataLoader.cpp
+++ b/engines/cruise/dataLoader.cpp
@@ -249,12 +249,19 @@ int loadFile(const char* name, int idx, int destIdx) {
int numMaxEntriesInSet = getNumMaxEntiresInSet(ptr);
if (destIdx > numMaxEntriesInSet) {
+ MemFree(ptr);
return 0; // exit if limit is reached
}
- return loadSetEntry(name, ptr, destIdx, idx);
+ int res = loadSetEntry(name, ptr, destIdx, idx);
+ MemFree(ptr);
+
+ return res;
}
case type_FNT: {
- return loadFNTSub(ptr, idx);
+ int res = loadFNTSub(ptr, idx);
+ MemFree(ptr);
+
+ return res;
}
case type_SPL: {
// Sound file
diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp
index 69e1bc4ad0..6f5d236173 100644
--- a/engines/cruise/detection.cpp
+++ b/engines/cruise/detection.cpp
@@ -35,7 +35,7 @@ struct CRUISEGameDescription {
};
const char *CruiseEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
Common::Language CruiseEngine::getLanguage() const {
@@ -196,8 +196,8 @@ static const CRUISEGameDescription gameDescriptions[] = {
class CruiseMetaEngine : public AdvancedMetaEngine {
public:
CruiseMetaEngine() : AdvancedMetaEngine(Cruise::gameDescriptions, sizeof(Cruise::CRUISEGameDescription), cruiseGames) {
- _singleid = "cruise";
- _guioptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI);
+ _singleId = "cruise";
+ _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI);
}
virtual const char *getName() const {
diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp
index f57435f4f7..b477dcdf9c 100644
--- a/engines/cruise/sound.cpp
+++ b/engines/cruise/sound.cpp
@@ -29,10 +29,11 @@
#include "cruise/sound.h"
#include "cruise/volume.h"
-#include "audio/audiostream.h"
#include "audio/fmopl.h"
-#include "audio/mixer.h"
-#include "audio/mods/soundfx.h"
+
+namespace Audio {
+class Mixer;
+}
namespace Cruise {
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
index 8498e50b8d..a21a4a8126 100644
--- a/engines/dialogs.cpp
+++ b/engines/dialogs.cpp
@@ -43,13 +43,13 @@
#include "engines/engine.h"
#include "engines/metaengine.h"
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
#include "gui/KeysDialog.h"
#endif
class ConfigDialog : public GUI::OptionsDialog {
protected:
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
GUI::Dialog *_keysDialog;
#endif
@@ -307,14 +307,14 @@ ConfigDialog::ConfigDialog(bool subtitleControls)
new GUI::ButtonWidget(this, "GlobalConfig.Ok", _("~O~K"), 0, GUI::kOKCmd);
new GUI::ButtonWidget(this, "GlobalConfig.Cancel", _("~C~ancel"), 0, GUI::kCloseCmd);
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
new GUI::ButtonWidget(this, "GlobalConfig.Keys", _("~K~eys"), 0, kKeysCmd);
_keysDialog = NULL;
#endif
}
ConfigDialog::~ConfigDialog() {
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
delete _keysDialog;
#endif
}
@@ -323,7 +323,7 @@ void ConfigDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32
switch (cmd) {
case kKeysCmd:
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
//
// Create the sub dialog(s)
//
diff --git a/engines/draci/detection.cpp b/engines/draci/detection.cpp
index 82b6935d72..65427bd8cd 100644
--- a/engines/draci/detection.cpp
+++ b/engines/draci/detection.cpp
@@ -84,7 +84,7 @@ const ADGameDescription gameDescriptions[] = {
class DraciMetaEngine : public AdvancedMetaEngine {
public:
DraciMetaEngine() : AdvancedMetaEngine(Draci::gameDescriptions, sizeof(ADGameDescription), draciGames) {
- _singleid = "draci";
+ _singleId = "draci";
}
virtual const char *getName() const {
diff --git a/engines/draci/draci.h b/engines/draci/draci.h
index 540c288d3d..90afdbcf60 100644
--- a/engines/draci/draci.h
+++ b/engines/draci/draci.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DRACI_H
-#define DRACI_H
+#ifndef DRACI_DRACI_H
+#define DRACI_DRACI_H
#include "engines/engine.h"
#include "common/random.h"
@@ -126,4 +126,4 @@ static inline long scummvm_lround(double val) { return (long)floor(val + 0.5); }
} // End of namespace Draci
-#endif // DRACI_H
+#endif // DRACI_DRACI_H
diff --git a/engines/draci/music.cpp b/engines/draci/music.cpp
index cda2007a8e..3fa380196a 100644
--- a/engines/draci/music.cpp
+++ b/engines/draci/music.cpp
@@ -22,10 +22,8 @@
// MIDI and digital music class
-#include "audio/audiostream.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
-#include "common/config-manager.h"
#include "common/debug.h"
#include "common/file.h"
diff --git a/engines/drascula/actors.cpp b/engines/drascula/actors.cpp
index 849e2ccd24..b459c4539b 100644
--- a/engines/drascula/actors.cpp
+++ b/engines/drascula/actors.cpp
@@ -123,6 +123,8 @@ void DrasculaEngine::startWalking() {
walkUp();
else if (roomY > curY + curHeight)
walkDown();
+ else
+ characterMoved = 0;
} else {
if ((roomX < curX + curWidth / 2 ) && (roomY <= (curY + curHeight)))
quadrant_1();
@@ -189,7 +191,7 @@ void DrasculaEngine::moveCharacters() {
}
if (currentChapter != 2 && currentChapter != 3) {
- if (hare_se_ve == 0) {
+ if (characterVisible == 0) {
increaseFrameNum();
return;
}
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index 5009a62e84..8b3299aaa9 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -116,7 +116,7 @@ void DrasculaEngine::animation_1_1() {
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit())
break;
- for (int l2 = 0; l2 < 3; l2++)
+ for (int l2 = 0; l2 < 3; l2++) {
for (int l = 0; l < 7; l++) {
copyBackground();
copyBackground(interf_x[l], interf_y[l], 156, 45, 63, 31, drawSurface2, screenSurface);
@@ -129,6 +129,9 @@ void DrasculaEngine::animation_1_1() {
}
if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit())
break;
+ }
+ if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit())
+ break;
for (int l = 0, l2 = 0, p = 0; l < 180; l++) {
copyBackground(0, 0, 320 - l, 0, l, 200, drawSurface3, screenSurface);
@@ -360,7 +363,7 @@ void DrasculaEngine::animation_2_1() {
int l;
gotoObject(231, 91);
- hare_se_ve = 0;
+ characterVisible = 0;
term_int = 0;
@@ -433,7 +436,7 @@ void DrasculaEngine::animation_2_1() {
curX = 91;
curY = 95;
trackProtagonist = 1;
- hare_se_ve = 1;
+ characterVisible = 1;
loadPic("97g.alg", extraSurface);
if (animate("lev.bin", 15))
@@ -1434,7 +1437,7 @@ void DrasculaEngine::animation_12_5() {
doBreak = 1;
previousMusic = roomMusic;
- hare_se_ve = 1;
+ characterVisible = 1;
clearRoom();
trackProtagonist = 1;
characterMoved = 0;
@@ -1504,6 +1507,7 @@ void DrasculaEngine::animation_14_5() {
void DrasculaEngine::animation_1_6() {
debug(4, "animation_1_6()");
+ hideCursor();
trackProtagonist = 0;
curX = 103;
curY = 108;
@@ -1543,7 +1547,7 @@ void DrasculaEngine::animation_1_6() {
updateEvents();
clearRoom();
black();
- hare_se_ve = 0;
+ characterVisible = 0;
flags[0] = 0;
updateRoom();
updateScreen();
@@ -1618,7 +1622,7 @@ void DrasculaEngine::animation_6_6() {
curX = -1;
selectVerb(kVerbNone);
enterRoom(58);
- hare_se_ve = 1;
+ characterVisible = 1;
trackProtagonist = 1;
animate("hbp.bin", 14);
@@ -2138,7 +2142,7 @@ void DrasculaEngine::animation_5_4(){
loadPic("anh_dr.alg", backSurface);
gotoObject(99, 160);
gotoObject(38, 177);
- hare_se_ve = 0;
+ characterVisible = 0;
updateRoom();
updateScreen();
delay(800);
@@ -2156,7 +2160,7 @@ void DrasculaEngine::animation_5_4(){
talk_igor(30, kIgorFront);
loadPic(96, frontSurface);
loadPic(99, backSurface);
- hare_se_ve = 1;
+ characterVisible = 1;
fadeToBlack(0);
exitRoom(0);
}
@@ -2211,7 +2215,7 @@ void DrasculaEngine::activatePendulum() {
debug(4, "activatePendulum()");
flags[1] = 2;
- hare_se_ve = 0;
+ characterVisible = 0;
_roomNumber = 102;
loadPic(102, bgSurface, HALF_PAL);
loadPic("an_p1.alg", drawSurface3);
diff --git a/engines/drascula/detection.cpp b/engines/drascula/detection.cpp
index 9a2da1d732..ffec393a0a 100644
--- a/engines/drascula/detection.cpp
+++ b/engines/drascula/detection.cpp
@@ -310,8 +310,8 @@ SaveStateDescriptor loadMetaData(Common::ReadStream *s, int slot, bool setPlayTi
class DrasculaMetaEngine : public AdvancedMetaEngine {
public:
DrasculaMetaEngine() : AdvancedMetaEngine(Drascula::gameDescriptions, sizeof(Drascula::DrasculaGameDescription), drasculaGames) {
- _singleid = "drascula";
- _guioptions = GUIO1(GUIO_NOMIDI);
+ _singleId = "drascula";
+ _guiOptions = GUIO1(GUIO_NOMIDI);
}
virtual const char *getName() const {
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index c72d77c281..ab91056480 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -23,19 +23,13 @@
#include "common/events.h"
#include "common/keyboard.h"
#include "common/file.h"
-#include "common/savefile.h"
#include "common/config-manager.h"
#include "common/textconsole.h"
#include "backends/audiocd/audiocd.h"
-#include "base/plugins.h"
-#include "base/version.h"
-
#include "engines/util.h"
-#include "audio/mixer.h"
-
#include "drascula/drascula.h"
#include "drascula/console.h"
@@ -144,7 +138,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
curDirection = 0;
trackProtagonist = 0;
_characterFrame = 0;
- hare_se_ve = 0;
+ characterVisible = 0;
roomX = 0;
roomY = 0;
checkFlags = 0;
@@ -183,9 +177,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
const Common::FSNode gameDataDir(ConfMan.get("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "audio");
- int cd_num = ConfMan.getInt("cdrom");
- if (cd_num >= 0)
- _system->getAudioCDManager()->openCD(cd_num);
+ _system->getAudioCDManager()->open();
_lang = kEnglish;
@@ -301,7 +293,7 @@ Common::Error DrasculaEngine::run() {
characterMoved = 0;
trackProtagonist = 3;
_characterFrame = 0;
- hare_se_ve = 1;
+ characterVisible = 1;
checkFlags = 1;
doBreak = 0;
walkToObject = 0;
@@ -367,7 +359,7 @@ Common::Error DrasculaEngine::run() {
for (i = 0; i < 25; i++)
memcpy(crosshairCursor + i * 40, tableSurface + 225 + (56 + i) * 320, 40);
- if (_lang == kSpanish)
+ if (_lang == kSpanish && currentChapter != 6)
loadPic(974, tableSurface);
if (currentChapter != 2) {
@@ -603,7 +595,6 @@ bool DrasculaEngine::runCurrentChapter() {
if (_rightMouseButton == 1 && _menuScreen) {
#endif
_rightMouseButton = 0;
- delay(100);
if (currentChapter == 2) {
loadPic(menuBackground, cursorSurface);
loadPic(menuBackground, backSurface);
@@ -632,7 +623,6 @@ bool DrasculaEngine::runCurrentChapter() {
!(currentChapter == 5 && pickedObject == 16)) {
#endif
_rightMouseButton = 0;
- delay(100);
characterMoved = 0;
if (trackProtagonist == 2)
trackProtagonist = 1;
@@ -660,12 +650,11 @@ bool DrasculaEngine::runCurrentChapter() {
#endif
if (_leftMouseButton == 1 && _menuBar) {
- delay(100);
selectVerbFromBar();
} else if (_leftMouseButton == 1 && takeObject == 0) {
- delay(100);
if (verify1())
return true;
+ delay(100);
} else if (_leftMouseButton == 1 && takeObject == 1) {
if (verify2())
return true;
@@ -899,7 +888,7 @@ void DrasculaEngine::pause(int duration) {
}
int DrasculaEngine::getTime() {
- return _system->getMillis() / 20; // originally was 1
+ return _system->getMillis() / 10;
}
void DrasculaEngine::reduce_hare_chico(int xx1, int yy1, int xx2, int yy2, int width, int height, int factor, byte *dir_inicio, byte *dir_fin) {
diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h
index 762add50a5..c879a83db7 100644
--- a/engines/drascula/drascula.h
+++ b/engines/drascula/drascula.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef DRASCULA_H
-#define DRASCULA_H
+#ifndef DRASCULA_DRASCULA_H
+#define DRASCULA_DRASCULA_H
#include "common/scummsys.h"
#include "common/archive.h"
@@ -429,7 +429,7 @@ public:
int frame_y;
int curX, curY, characterMoved, curDirection, trackProtagonist, _characterFrame;
- int hare_se_ve; // TODO: what is this for?
+ int characterVisible;
int roomX, roomY, checkFlags;
int doBreak;
int stepX, stepY;
@@ -784,4 +784,4 @@ protected:
} // End of namespace Drascula
-#endif /* DRASCULA_H */
+#endif /* DRASCULA_DRASCULA_H */
diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp
index 077047a6eb..6bfb2e1823 100644
--- a/engines/drascula/graphics.cpp
+++ b/engines/drascula/graphics.cpp
@@ -217,6 +217,10 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
int letterY = 0, letterX = 0, i;
uint len = strlen(said);
byte c;
+
+ byte *srcSurface = tableSurface;
+ if (_lang == kSpanish && currentChapter == 6)
+ srcSurface = extraSurface;
for (uint h = 0; h < len; h++) {
c = toupper(said[h]);
@@ -241,7 +245,7 @@ void DrasculaEngine::print_abc(const char *said, int screenX, int screenY) {
} // for
copyRect(letterX, letterY, screenX, screenY,
- CHAR_WIDTH, CHAR_HEIGHT, tableSurface, screenSurface);
+ CHAR_WIDTH, CHAR_HEIGHT, srcSurface, screenSurface);
screenX = screenX + CHAR_WIDTH;
if (screenX > 317) {
@@ -319,28 +323,51 @@ int DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) {
}
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;
+ int textLen = strlen(text);
+ int halfLen = (textLen / 2) * CHAR_WIDTH;
+
+ //if (x > 160)
+ // x = 315 - x;
+ //return (halfLen <= x);
+
+ // The commented out code above is what the original engine is doing. Instead of testing the
+ // upper bound if x is greater than 160 it takes the complement to 315 and test only the lower
+ // bounds.
+ // Also note that since it does an integer division to compute the half length of the string,
+ // in the case where the string has an odd number of characters there is one more character to
+ // the right than to the left. If the string center is beyond 160, this is taken care of by
+ // taking the complement to 315 instead of 320. But if the string center is close to the screen
+ // center, but not greater than 160, this can lead to the string being accepted despite having
+ // one character beyond the right edge of the screen.
+ // In ScummVM we therefore also test the right edge, which leads to differences
+ // with the original engine, but for the better.
+ if (x > 160)
+ return (315 - x - halfLen >= 0);
+ return (x - halfLen >= 0 && x + halfLen + (textLen % 2) * CHAR_WIDTH <= 320);
}
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);
-
Common::strlcpy(msg, message, 200);
+
+ // We make sure to have a width of at least 120 pixels by clipping the center.
+ // In theory since the screen width is 320 I would expect something like this:
+ // x = CLIP<int>(x, 60, 260);
+ // return (x - halfLen >= 0 && x + halfLen <= 319);
+
+ // The engines does things differently though. It tries to clips text at 315 instead of 319.
+ // See also the comment in textFitsCentered().
+
+ textX = CLIP<int>(textX, 60, 255);
// 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);
+ int x = textX - (strlen(msg) / 2) * CHAR_WIDTH - 1;
+ // The original starts to draw (nbLines + 2) lines above textY, except if there is a single line
+ // in which case it starts drawing at (nbLines + 3) above textY.
+ // Also clip to the screen height although the original does not do it.
+ int y = textY - 4 * CHAR_HEIGHT;
+ y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT);
print_abc(msg, x, y);
return;
}
@@ -351,42 +378,61 @@ void DrasculaEngine::centerText(const char *message, int textX, int textY) {
// with the German translation.
if (!strchr(msg, ' ')) {
int len = strlen(msg);
- x = CLIP<int>(textX - len * CHAR_WIDTH / 2, 0, 319 - len * CHAR_WIDTH);
+ int x = CLIP<int>(textX - (len / 2) * CHAR_WIDTH - 1, 0, 319 - len * CHAR_WIDTH);
+ int y = textY - 4 * CHAR_HEIGHT;
+ y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT);
print_abc(msg, x, y);
return;
}
// Message doesn't fit on screen, split it
-
+ char messageLines[15][41]; // screenWidth/charWidth = 320/8 = 40. Thus lines can have up to 41 characters with the null terminator (despite the original allocating only 40 characters here).
+ int curLine = 0;
+ char messageCurLine[50];
+ char tmpMessageCurLine[50];
+ *messageCurLine = 0;
+ *tmpMessageCurLine = 0;
// Get a word from the message
- curWord = strtok(msg, " ");
+ char* curWord = strtok(msg, " ");
while (curWord != NULL) {
// Check if the word and the current line fit on screen
- if (tmpMessageLine[0] != '\0')
- Common::strlcat(tmpMessageLine, " ", 200);
- Common::strlcat(tmpMessageLine, curWord, 200);
- if (textFitsCentered(tmpMessageLine, textX)) {
+ if (tmpMessageCurLine[0] != '\0')
+ Common::strlcat(tmpMessageCurLine, " ", 50);
+ Common::strlcat(tmpMessageCurLine, curWord, 50);
+ if (textFitsCentered(tmpMessageCurLine, textX)) {
// Line fits, so add the word to the current message line
- strcpy(messageLine, tmpMessageLine);
+ strcpy(messageCurLine, tmpMessageCurLine);
} 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);
- Common::strlcpy(messageLine, curWord, 200);
- Common::strlcpy(tmpMessageLine, curWord, 200);
- curLine++;
+ // Line does't fit. Store the current line and start a new line.
+ Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
+ Common::strlcpy(messageCurLine, curWord, 50);
+ Common::strlcpy(tmpMessageCurLine, curWord, 50);
}
// Get next word
curWord = strtok(NULL, " ");
-
if (curWord == NULL) {
- x = CLIP<int>(textX - strlen(messageLine) * CHAR_WIDTH / 2, 60, 255);
- print_abc(messageLine, x, y + curLine * CHAR_HEIGHT);
+ // The original has an interesting bug that if we split the text on several lines
+ // a space is added at the end (which impacts the alignment, and may even cause the line
+ // to become too long).
+ Common::strlcat(messageCurLine, " ", 50);
+ if (!textFitsCentered(messageCurLine, textX)) {
+ messageCurLine[strlen(messageCurLine) - 1] = '\0';
+ Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
+ strcpy(messageLines[curLine++], " ");
+ } else
+ Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
}
}
+
+ // The original starts to draw (nbLines + 2) lines above textY.
+ // Also clip to the screen height although the original does not do it.
+ int y = textY - (curLine + 2) * CHAR_HEIGHT;
+ y = CLIP<int>(y, 0, 200 - curLine * (CHAR_HEIGHT + 2) + 2);
+ for (int line = 0 ; line < curLine ; ++line, y += CHAR_HEIGHT + 2) {
+ int textHalfLen = (strlen(messageLines[line]) / 2) * CHAR_WIDTH;
+ print_abc(messageLines[line], textX - textHalfLen - 1, y);
+ }
}
void DrasculaEngine::screenSaver() {
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index cd7d502194..02846abcc9 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -62,7 +62,7 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) {
hideCursor();
if (currentChapter == 5 || currentChapter == 6) {
- if (hare_se_ve == 0) {
+ if (characterVisible == 0) {
curX = roomX;
curY = roomY;
updateRoom();
@@ -272,6 +272,8 @@ void DrasculaEngine::updateVisible() {
visible[2] = 0;
if (_roomNumber == 26 && flags[12] == 1)
visible[1] = 0;
+ if (_roomNumber == 31 && flags[13] == 1)
+ visible[1] = 0;
if (_roomNumber == 35 && flags[14] == 1)
visible[2] = 0;
if (_roomNumber == 35 && flags[17] == 1)
diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp
index 8691bd2cb4..57d4517295 100644
--- a/engines/drascula/rooms.cpp
+++ b/engines/drascula/rooms.cpp
@@ -980,12 +980,12 @@ bool DrasculaEngine::room_59(int fl) {
playSound(12);
pause(19);
stopSound();
- hare_se_ve = 0;
+ characterVisible = 0;
updateRoom();
copyRect(101, 34, curX - 4, curY - 1, 37, 70, drawSurface3, screenSurface);
copyBackground(0, 0, 0, 0, 320, 200, screenSurface, bgSurface);
updateScreen();
- hare_se_ve = 1;
+ characterVisible = 1;
clearRoom();
loadPic("tlef0.alg", bgSurface, COMPLETE_PAL);
loadPic("tlef1.alg", drawSurface3);
@@ -1399,7 +1399,7 @@ void DrasculaEngine::update_58_pre() {
}
void DrasculaEngine::update_58() {
- if (hare_se_ve == 1)
+ if (characterVisible == 1)
copyRect(67, 139, 140, 147, 12, 16, drawSurface3, screenSurface);
}
@@ -1845,7 +1845,7 @@ void DrasculaEngine::enterRoom(int roomIndex) {
}
if (currentChapter == 5)
- hare_se_ve = 1;
+ characterVisible = 1;
updateVisible();
@@ -1885,7 +1885,7 @@ void DrasculaEngine::enterRoom(int roomIndex) {
if (currentChapter == 5) {
if (_roomNumber == 45)
- hare_se_ve = 0;
+ characterVisible = 0;
if (_roomNumber == 49 && flags[7] == 0) {
playTalkSequence(4); // sequence 4, chapter 5
}
@@ -1961,7 +1961,7 @@ bool DrasculaEngine::exitRoom(int doorNumber) {
}
if (currentChapter == 5)
- hare_se_ve = 1;
+ characterVisible = 1;
clearRoom();
if (!sscanf(_targetSurface[doorNumber], "%d", &roomNum)) {
diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp
index d0f16aa941..eb72a999d4 100644
--- a/engines/drascula/saveload.cpp
+++ b/engines/drascula/saveload.cpp
@@ -255,6 +255,19 @@ bool DrasculaEngine::loadGame(int slot) {
if (!(in = _saveFileMan->openForLoading(saveFileName))) {
error("missing savegame file %s", saveFileName.c_str());
}
+
+ // If we currently are in room 102 while being attached below the pendulum
+ // the character is invisible and some surface are temporarily used for other
+ // things. Reset those before loading the savegame otherwise we may have some
+ // issues such as the protagonist being invisible after reloading a savegame.
+ if (_roomNumber == 102 && flags[1] == 2) {
+ characterVisible = 1;
+ loadPic(96, frontSurface);
+ loadPic(97, frontSurface);
+ loadPic(97, extraSurface);
+ loadPic(99, backSurface);
+ }
+
loadMetaData(in, slot, true);
Graphics::skipThumbnail(*in);
@@ -287,8 +300,23 @@ bool DrasculaEngine::loadGame(int slot) {
if (!sscanf(currentData, "%d.ald", &roomNum)) {
error("Bad save format");
}
+
+ // When loading room 102 while being attached below the pendulum Some variables
+ // are not correctly set and can cause random crashes when calling enterRoom below.
+ // The crash occurs in moveCharacters() when accessing factor_red[curY + curHeight].
+ if (roomNum == 102 && flags[1] == 2) {
+ curX = 103;
+ curY = 108;
+ curWidth = curHeight = 0;
+ }
+
enterRoom(roomNum);
selectVerb(kVerbNone);
+
+ // When loading room 102 while being attached below the pendulum we
+ // need to call activatePendulum() to properly initialized the scene.
+ if (_roomNumber == 102 && flags[1] == 2)
+ activatePendulum();
return true;
}
diff --git a/engines/drascula/sound.cpp b/engines/drascula/sound.cpp
index 148dae76f5..62ec796678 100644
--- a/engines/drascula/sound.cpp
+++ b/engines/drascula/sound.cpp
@@ -44,7 +44,7 @@ void DrasculaEngine::updateVolume(Audio::Mixer::SoundType soundType, int prevVol
}
void DrasculaEngine::volumeControls() {
- if (_lang == kSpanish)
+ if (_lang == kSpanish && currentChapter != 6)
loadPic(95, tableSurface);
copyRect(1, 56, 73, 63, 177, 97, tableSurface, screenSurface);
@@ -101,7 +101,7 @@ void DrasculaEngine::volumeControls() {
}
- if (_lang == kSpanish)
+ if (_lang == kSpanish && currentChapter != 6)
loadPic(974, tableSurface);
selectVerb(kVerbNone);
@@ -133,7 +133,7 @@ void DrasculaEngine::stopMusic() {
}
void DrasculaEngine::updateMusic() {
- _system->getAudioCDManager()->updateCD();
+ _system->getAudioCDManager()->update();
}
int DrasculaEngine::musicStatus() {
@@ -166,8 +166,8 @@ void DrasculaEngine::MusicFadeout() {
void DrasculaEngine::playFile(const char *fname) {
Common::SeekableReadStream *stream = _archives.open(fname);
if (stream) {
- int startOffset = 0;
- int soundSize = stream->size() - startOffset;
+ int startOffset = 32;
+ int soundSize = stream->size() - 64;
if (!strcmp(fname, "3.als") && soundSize == 145166 && _lang != kSpanish) {
// WORKAROUND: File 3.als with English speech files has a big silence at
diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp
index e9fec868f8..cc329b206b 100644
--- a/engines/drascula/talk.cpp
+++ b/engines/drascula/talk.cpp
@@ -232,7 +232,7 @@ void DrasculaEngine::talk_solo(const char *said, const char *filename) {
if (currentChapter == 1)
color_abc(color_solo);
- else if (currentChapter == 4)
+ else if (currentChapter == 5)
color_abc(kColorRed);
talkInit(filename);
diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp
index 853047ccc7..8e24c44702 100644
--- a/engines/dreamweb/detection.cpp
+++ b/engines/dreamweb/detection.cpp
@@ -23,6 +23,7 @@
#include "base/plugins.h"
#include "common/algorithm.h"
+#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
@@ -70,8 +71,8 @@ public:
AdvancedMetaEngine(DreamWeb::gameDescriptions,
sizeof(DreamWeb::DreamWebGameDescription), dreamWebGames,
gameGuiOptions) {
- _singleid = "dreamweb";
- _guioptions = GUIO1(GUIO_NOMIDI);
+ _singleId = "dreamweb";
+ _guiOptions = GUIO1(GUIO_NOMIDI);
}
virtual const char *getName() const {
diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h
index cb9bebb304..0a59543c51 100644
--- a/engines/dreamweb/detection_tables.h
+++ b/engines/dreamweb/detection_tables.h
@@ -244,6 +244,26 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
},
+ // Czech fan-made translation
+ // From bug #7078
+ {
+ {
+ "dreamweb",
+ "CD",
+ {
+ {"dreamweb.r00", 0, "3b5c87717fc40cc5a5ae19c155662ee3", 152918},
+ {"dreamweb.r02", 0, "28458718167a040d7e988cf7d2298eae", 210466},
+ {"dreamweb.exe", 0, "40cc15bdc8fa3a785b5fd1ecd6194119", 65440},
+ AD_LISTEND
+ },
+ Common::CZ_CZE,
+ Common::kPlatformDOS,
+ ADGF_CD,
+ GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
+ },
+ },
+
+
{ AD_TABLE_END_MARKER }
};
diff --git a/engines/dreamweb/dreamweb.h b/engines/dreamweb/dreamweb.h
index e39f8c0d51..45bacdba86 100644
--- a/engines/dreamweb/dreamweb.h
+++ b/engines/dreamweb/dreamweb.h
@@ -20,21 +20,16 @@
*
*/
-#ifndef DREAMWEB_H
-#define DREAMWEB_H
+#ifndef DREAMWEB_DREAMWEB_H
+#define DREAMWEB_DREAMWEB_H
#include "common/error.h"
-#include "common/file.h"
#include "common/keyboard.h"
#include "common/random.h"
#include "common/rect.h"
-#include "common/savefile.h"
#include "common/scummsys.h"
#include "common/system.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-
#include "engines/engine.h"
#include "dreamweb/console.h"
@@ -45,6 +40,10 @@
#define SCUMMVM_BLOCK_MAGIC_SIZE 0x1234
#define SAVEGAME_VERSION 1
+namespace Common {
+class File;
+}
+
namespace DreamWeb {
const unsigned int kNumReelRoutines = 57;
diff --git a/engines/dreamweb/saveload.cpp b/engines/dreamweb/saveload.cpp
index ce89dae732..a104ba727d 100644
--- a/engines/dreamweb/saveload.cpp
+++ b/engines/dreamweb/saveload.cpp
@@ -28,6 +28,7 @@
#include "gui/saveload.h"
#include "common/config-manager.h"
#include "common/translation.h"
+#include "common/savefile.h"
#include "common/serializer.h"
namespace DreamWeb {
diff --git a/engines/dreamweb/sound.cpp b/engines/dreamweb/sound.cpp
index d3b417de90..2a4cd9c75c 100644
--- a/engines/dreamweb/sound.cpp
+++ b/engines/dreamweb/sound.cpp
@@ -25,6 +25,8 @@
#include "common/debug.h"
#include "common/file.h"
+#include "audio/audiostream.h"
+
#include "dreamweb/dreamweb.h"
#include "dreamweb/sound.h"
diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp
index 68b223392c..4aa487d13f 100644
--- a/engines/dreamweb/stubs.cpp
+++ b/engines/dreamweb/stubs.cpp
@@ -23,6 +23,7 @@
#include "dreamweb/sound.h"
#include "dreamweb/dreamweb.h"
#include "common/config-manager.h"
+#include "common/file.h"
namespace DreamWeb {
diff --git a/engines/dreamweb/vgagrafx.cpp b/engines/dreamweb/vgagrafx.cpp
index c59d3e3ad5..4a7acd2344 100644
--- a/engines/dreamweb/vgagrafx.cpp
+++ b/engines/dreamweb/vgagrafx.cpp
@@ -21,6 +21,7 @@
*/
#include "dreamweb/dreamweb.h"
+#include "common/file.h"
#include "engines/util.h"
#include "graphics/surface.h"
#include "image/pcx.h"
diff --git a/engines/engine.cpp b/engines/engine.cpp
index d3b9b113cf..8fff99f3fc 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -269,8 +269,8 @@ void splashScreen() {
// Load logo
Graphics::Surface *logo = bitmap.getSurface()->convertTo(g_system->getOverlayFormat(), bitmap.getPalette());
- int lx = (g_system->getOverlayWidth() - logo->w) / 2;
- int ly = (g_system->getOverlayHeight() - logo->h) / 2;
+ int lx = MAX((g_system->getOverlayWidth() - logo->w) / 2, 0);
+ int ly = MAX((g_system->getOverlayHeight() - logo->h) / 2, 0);
// Print version information
const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont);
@@ -283,7 +283,10 @@ void splashScreen() {
screen.free();
// Draw logo
- g_system->copyRectToOverlay(logo->getPixels(), logo->pitch, lx, ly, logo->w, logo->h);
+ int lw = MIN<uint16>(logo->w, g_system->getOverlayWidth() - lx);
+ int lh = MIN<uint16>(logo->h, g_system->getOverlayHeight() - ly);
+
+ g_system->copyRectToOverlay(logo->getPixels(), logo->pitch, lx, ly, lw, lh);
logo->free();
delete logo;
diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp
index 14e9c33bdf..c90b2b07da 100644
--- a/engines/fullpipe/behavior.cpp
+++ b/engines/fullpipe/behavior.cpp
@@ -40,8 +40,8 @@ BehaviorManager::~BehaviorManager() {
void BehaviorManager::clear() {
for (uint i = 0; i < _behaviors.size(); i++) {
- for (int j = 0; j < _behaviors[i]->_itemsCount; j++)
- delete _behaviors[i]->_bheItems[j];
+ for (int j = 0; j < _behaviors[i]->_animsCount; j++)
+ delete _behaviors[i]->_behaviorAnims[j];
delete _behaviors[i];
}
@@ -90,7 +90,7 @@ void BehaviorManager::updateBehaviors() {
if (!beh->_ani) {
beh->_counter++;
if (beh->_counter >= beh->_counterMax)
- updateBehavior(beh, beh->_bheItems[0]);
+ updateBehavior(beh, beh->_behaviorAnims[0]);
continue;
}
@@ -104,15 +104,15 @@ void BehaviorManager::updateBehaviors() {
beh->_counter++;
if (beh->_counter >= beh->_counterMax) {
if (beh->_subIndex >= 0 && !(beh->_flags & 1) && beh->_ani->_messageQueueId <= 0)
- updateStaticAniBehavior(beh->_ani, beh->_counter, beh->_bheItems[beh->_subIndex]);
+ updateStaticAniBehavior(beh->_ani, beh->_counter, beh->_behaviorAnims[beh->_subIndex]);
}
} else {
beh->_staticsId = beh->_ani->_statics->_staticsId;
beh->_counter = 0;
beh->_subIndex = -1;
- for (int j = 0; j < beh->_itemsCount; j++)
- if (beh->_bheItems[j]->_staticsId == beh->_staticsId) {
+ for (int j = 0; j < beh->_animsCount; j++)
+ if (beh->_behaviorAnims[j]->_staticsId == beh->_staticsId) {
beh->_subIndex = j;
break;
}
@@ -121,10 +121,10 @@ void BehaviorManager::updateBehaviors() {
}
}
-void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry) {
- debug(4, "BehaviorManager::updateBehavior() %d", entry->_itemsCount);
- for (int i = 0; i < entry->_itemsCount; i++) {
- BehaviorEntryInfo *bhi = entry->_items[i];
+void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorAnim *entry) {
+ debug(4, "BehaviorManager::updateBehavior() %d", entry->_movesCount);
+ for (int i = 0; i < entry->_movesCount; i++) {
+ BehaviorMove *bhi = entry->_behaviorMoves[i];
if (!(bhi->_flags & 1)) {
if (bhi->_flags & 2) {
MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1);
@@ -132,7 +132,7 @@ void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *
mq->sendNextCommand();
bhi->_flags &= 0xFFFFFFFD;
- } else if (behaviorInfo->_counter >= bhi->_delay && bhi->_percent && g_fp->_rnd->getRandomNumber(32767) <= entry->_items[i]->_percent) {
+ } else if (behaviorInfo->_counter >= bhi->_delay && bhi->_percent && g_fp->_rnd->getRandomNumber(32767) <= entry->_behaviorMoves[i]->_percent) {
MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1);
mq->sendNextCommand();
@@ -143,7 +143,7 @@ void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *
}
}
-void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *bhe) {
+void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorAnim *bhe) {
debug(4, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName));
MessageQueue *mq = 0;
@@ -151,21 +151,21 @@ void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, B
if (bhe->_flags & 1) {
uint rnd = g_fp->_rnd->getRandomNumber(32767);
uint runPercent = 0;
- for (int i = 0; i < bhe->_itemsCount; i++) {
- if (!(bhe->_items[i]->_flags & 1) && bhe->_items[i]->_percent) {
- if ((rnd >= runPercent && rnd <= runPercent + bhe->_items[i]->_percent) || i == bhe->_itemsCount - 1) {
- mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1);
+ for (int i = 0; i < bhe->_movesCount; i++) {
+ if (!(bhe->_behaviorMoves[i]->_flags & 1) && bhe->_behaviorMoves[i]->_percent) {
+ if ((rnd >= runPercent && rnd <= runPercent + bhe->_behaviorMoves[i]->_percent) || i == bhe->_movesCount - 1) {
+ mq = new MessageQueue(bhe->_behaviorMoves[i]->_messageQueue, 0, 1);
break;
}
- runPercent += bhe->_items[i]->_percent;
+ runPercent += bhe->_behaviorMoves[i]->_percent;
}
}
} else {
- for (int i = 0; i < bhe->_itemsCount; i++) {
- if (!(bhe->_items[i]->_flags & 1) && delay >= bhe->_items[i]->_delay) {
- if (bhe->_items[i]->_percent) {
- if (g_fp->_rnd->getRandomNumber(32767) <= bhe->_items[i]->_percent) {
- mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1);
+ for (int i = 0; i < bhe->_movesCount; i++) {
+ if (!(bhe->_behaviorMoves[i]->_flags & 1) && delay >= bhe->_behaviorMoves[i]->_delay) {
+ if (bhe->_behaviorMoves[i]->_percent) {
+ if (g_fp->_rnd->getRandomNumber(32767) <= bhe->_behaviorMoves[i]->_percent) {
+ mq = new MessageQueue(bhe->_behaviorMoves[i]->_messageQueue, 0, 1);
break;
}
}
@@ -180,7 +180,7 @@ void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, B
}
bool BehaviorManager::setBehaviorEnabled(StaticANIObject *obj, int aniId, int quId, int flag) {
- BehaviorEntryInfo *entry = getBehaviorEntryInfoByMessageQueueDataId(obj, aniId, quId);
+ BehaviorMove *entry = getBehaviorMoveByMessageQueueDataId(obj, aniId, quId);
if (entry) {
if (flag)
@@ -206,14 +206,14 @@ void BehaviorManager::setFlagByStaticAniObject(StaticANIObject *ani, int flag) {
}
}
-BehaviorEntryInfo *BehaviorManager::getBehaviorEntryInfoByMessageQueueDataId(StaticANIObject *ani, int id1, int id2) {
+BehaviorMove *BehaviorManager::getBehaviorMoveByMessageQueueDataId(StaticANIObject *ani, int id1, int id2) {
for (uint i = 0; i < _behaviors.size(); i++) {
if (_behaviors[i]->_ani == ani) {
- for (uint j = 0; j < _behaviors[i]->_bheItems.size(); j++) {
- if (_behaviors[i]->_bheItems[j]->_staticsId == id1) {
- for (int k = 0; k < _behaviors[i]->_bheItems[j]->_itemsCount; k++) {
- if (_behaviors[i]->_bheItems[j]->_items[k]->_messageQueue->_dataId == id2)
- return _behaviors[i]->_bheItems[j]->_items[k];
+ for (uint j = 0; j < _behaviors[i]->_behaviorAnims.size(); j++) {
+ if (_behaviors[i]->_behaviorAnims[j]->_staticsId == id1) {
+ for (int k = 0; k < _behaviors[i]->_behaviorAnims[j]->_movesCount; k++) {
+ if (_behaviors[i]->_behaviorAnims[j]->_behaviorMoves[k]->_messageQueue->_dataId == id2)
+ return _behaviors[i]->_behaviorAnims[j]->_behaviorMoves[k];
}
}
}
@@ -230,32 +230,32 @@ void BehaviorInfo::clear() {
_counterMax = 0;
_flags = 0;
_subIndex = 0;
- _itemsCount = 0;
+ _animsCount = 0;
- _bheItems.clear();
+ _behaviorAnims.clear();
}
void BehaviorInfo::initAmbientBehavior(GameVar *var, Scene *sc) {
debug(4, "BehaviorInfo::initAmbientBehavior(%s)", transCyrillic((byte *)var->_varName));
clear();
- _itemsCount = 1;
+ _animsCount = 1;
_counterMax = -1;
- BehaviorEntry *bi = new BehaviorEntry();
+ BehaviorAnim *bi = new BehaviorAnim();
- _bheItems.push_back(bi);
+ _behaviorAnims.push_back(bi);
- bi->_itemsCount = var->getSubVarsCount();
+ bi->_movesCount = var->getSubVarsCount();
- bi->_items = (BehaviorEntryInfo**)calloc(bi->_itemsCount, sizeof(BehaviorEntryInfo *));
+ bi->_behaviorMoves = (BehaviorMove **)calloc(bi->_movesCount, sizeof(BehaviorMove *));
- for (int i = 0; i < bi->_itemsCount; i++) {
+ for (int i = 0; i < bi->_movesCount; i++) {
int delay;
- bi->_items[i] = new BehaviorEntryInfo(var->getSubVarByIndex(i), sc, &delay);
+ bi->_behaviorMoves[i] = new BehaviorMove(var->getSubVarByIndex(i), sc, &delay);
- if (bi->_items[i]->_delay <_counterMax)
- _counterMax = bi->_items[i]->_delay;
+ if (bi->_behaviorMoves[i]->_delay <_counterMax)
+ _counterMax = bi->_behaviorMoves[i]->_delay;
}
}
@@ -264,7 +264,7 @@ void BehaviorInfo::initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *
clear();
- _itemsCount = var->getSubVarsCount();
+ _animsCount = var->getSubVarsCount();
_counterMax = -1;
while (var->_varType == 2) {
@@ -278,54 +278,54 @@ void BehaviorInfo::initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *
sc = g_fp->accessScene(ani->_sceneId);
clear();
var = v1;
- _itemsCount = var->getSubVarsCount();
+ _animsCount = var->getSubVarsCount();
_counterMax = -1;
}
- for (int i = 0; i < _itemsCount; i++) {
+ for (int i = 0; i < _animsCount; i++) {
int maxDelay = 0;
- _bheItems.push_back(new BehaviorEntry(var->getSubVarByIndex(i), sc, ani, &maxDelay));
+ _behaviorAnims.push_back(new BehaviorAnim(var->getSubVarByIndex(i), sc, ani, &maxDelay));
if (maxDelay < _counterMax)
_counterMax = maxDelay;
}
}
-BehaviorEntry::BehaviorEntry() {
+BehaviorAnim::BehaviorAnim() {
_staticsId = 0;
- _itemsCount = 0;
+ _movesCount = 0;
_flags = 0;
- _items = 0;
+ _behaviorMoves = NULL;
}
-BehaviorEntry::BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) {
+BehaviorAnim::BehaviorAnim(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) {
_staticsId = 0;
- _itemsCount = 0;
+ _movesCount = 0;
*minDelay = 100000000;
int totalPercent = 0;
_flags = 0;
- _items = 0;
+ _behaviorMoves = 0;
Statics *st = ani->getStaticsByName(var->_varName);
if (st)
_staticsId = st->_staticsId;
- _itemsCount = var->getSubVarsCount();
- if (_itemsCount) {
- _items = (BehaviorEntryInfo**)calloc(_itemsCount, sizeof(BehaviorEntryInfo *));
+ _movesCount = var->getSubVarsCount();
+ if (_movesCount) {
+ _behaviorMoves = (BehaviorMove **)calloc(_movesCount, sizeof(BehaviorMove *));
- for (int i = 0; i < _itemsCount; i++) {
+ for (int i = 0; i < _movesCount; i++) {
GameVar *subvar = var->getSubVarByIndex(i);
int delay = 0;
- _items[i] = new BehaviorEntryInfo(subvar, sc, &delay);
+ _behaviorMoves[i] = new BehaviorMove(subvar, sc, &delay);
totalPercent += delay;
- if (_items[i]->_delay < *minDelay)
- *minDelay = _items[i]->_delay;
+ if (_behaviorMoves[i]->_delay < *minDelay)
+ *minDelay = _behaviorMoves[i]->_delay;
}
if (!*minDelay && totalPercent == 1000)
@@ -333,7 +333,7 @@ BehaviorEntry::BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int
}
}
-BehaviorEntryInfo::BehaviorEntryInfo(GameVar *subvar, Scene *sc, int *delay) {
+BehaviorMove::BehaviorMove(GameVar *subvar, Scene *sc, int *delay) {
_messageQueue = 0;
_delay = 0;
_percent = 0;
diff --git a/engines/fullpipe/behavior.h b/engines/fullpipe/behavior.h
index 1ec98d5bf2..e534371442 100644
--- a/engines/fullpipe/behavior.h
+++ b/engines/fullpipe/behavior.h
@@ -25,23 +25,23 @@
namespace Fullpipe {
-struct BehaviorEntryInfo {
+struct BehaviorMove {
MessageQueue *_messageQueue;
int _delay;
uint32 _percent;
int _flags;
- BehaviorEntryInfo(GameVar *subvar, Scene *sc, int *delay);
+ BehaviorMove(GameVar *subvar, Scene *sc, int *delay);
};
-struct BehaviorEntry {
+struct BehaviorAnim {
int _staticsId;
- int _itemsCount;
+ int _movesCount;
int _flags;
- BehaviorEntryInfo **_items;
+ BehaviorMove **_behaviorMoves;
- BehaviorEntry();
- BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay);
+ BehaviorAnim();
+ BehaviorAnim(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay);
};
struct BehaviorInfo {
@@ -51,8 +51,8 @@ struct BehaviorInfo {
int _counterMax;
int _flags;
int _subIndex;
- int _itemsCount;
- Common::Array<BehaviorEntry *> _bheItems;
+ int _animsCount;
+ Common::Array<BehaviorAnim *> _behaviorAnims;
BehaviorInfo() { clear(); }
@@ -75,14 +75,14 @@ class BehaviorManager : public CObject {
void initBehavior(Scene *scene, GameVar *var);
void updateBehaviors();
- void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry);
- void updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *beh);
+ void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorAnim *entry);
+ void updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorAnim *beh);
bool setBehaviorEnabled(StaticANIObject *obj, int aniId, int quId, int flag);
void setFlagByStaticAniObject(StaticANIObject *ani, int flag);
- BehaviorEntryInfo *getBehaviorEntryInfoByMessageQueueDataId(StaticANIObject *ani, int id1, int id2);
+ BehaviorMove *getBehaviorMoveByMessageQueueDataId(StaticANIObject *ani, int id1, int id2);
};
} // End of namespace Fullpipe
diff --git a/engines/fullpipe/configure.engine b/engines/fullpipe/configure.engine
index a9042449db..611d0188dc 100644
--- a/engines/fullpipe/configure.engine
+++ b/engines/fullpipe/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine fullpipe "Full Pipe" no "" "" "16bit"
+add_engine fullpipe "Full Pipe" no "" "" "16bit highres"
diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp
index 99fbdc4b82..6f92f19f24 100644
--- a/engines/fullpipe/detection.cpp
+++ b/engines/fullpipe/detection.cpp
@@ -32,7 +32,7 @@
namespace Fullpipe {
const char *FullpipeEngine::getGameId() const {
- return _gameDescription->gameid;
+ return _gameDescription->gameId;
}
}
@@ -76,7 +76,7 @@ static const ADGameDescription gameDescriptions[] = {
class FullpipeMetaEngine : public AdvancedMetaEngine {
public:
FullpipeMetaEngine() : AdvancedMetaEngine(Fullpipe::gameDescriptions, sizeof(ADGameDescription), fullpipeGames) {
- _singleid = "fullpipe";
+ _singleId = "fullpipe";
}
virtual const char *getName() const {
diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp
index ebaff32550..c2aae9ba88 100644
--- a/engines/fullpipe/fullpipe.cpp
+++ b/engines/fullpipe/fullpipe.cpp
@@ -24,6 +24,7 @@
#include "common/archive.h"
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "engines/util.h"
@@ -112,6 +113,8 @@ FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc)
_musicLocal = 0;
_trackStartDelay = 0;
+ _sceneTrackHandle = new Audio::SoundHandle();
+
memset(_sceneTracks, 0, sizeof(_sceneTracks));
memset(_trackName, 0, sizeof(_trackName));
memset(_sceneTracksCurrentTrack, 0, sizeof(_sceneTracksCurrentTrack));
@@ -192,6 +195,7 @@ FullpipeEngine::~FullpipeEngine() {
delete _rnd;
delete _console;
delete _globalMessageQueueList;
+ delete _sceneTrackHandle;
}
void FullpipeEngine::initialize() {
diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h
index 7f20a6d6af..fba61aa13b 100644
--- a/engines/fullpipe/fullpipe.h
+++ b/engines/fullpipe/fullpipe.h
@@ -30,8 +30,6 @@
#include "common/savefile.h"
#include "common/system.h"
-#include "audio/mixer.h"
-
#include "graphics/transparent_surface.h"
#include "engines/engine.h"
@@ -41,6 +39,10 @@
struct ADGameDescription;
+namespace Audio {
+class SoundHandle;
+}
+
namespace Fullpipe {
enum FullpipeGameFeatures {
@@ -312,7 +314,7 @@ public:
void lift_openLift();
GameVar *_musicGameVar;
- Audio::SoundHandle _sceneTrackHandle;
+ Audio::SoundHandle *_sceneTrackHandle;
public:
diff --git a/engines/fullpipe/gameloader.cpp b/engines/fullpipe/gameloader.cpp
index 68b63d398a..3a0e262f82 100644
--- a/engines/fullpipe/gameloader.cpp
+++ b/engines/fullpipe/gameloader.cpp
@@ -110,10 +110,10 @@ GameLoader::~GameLoader() {
}
bool GameLoader::load(MfcArchive &file) {
- debug(5, "GameLoader::load()");
+ debug(1, "GameLoader::load()");
_gameName = file.readPascalString();
- debug(6, "_gameName: %s", _gameName);
+ debug(1, "_gameName: %s", _gameName);
_gameProject = new GameProject();
@@ -126,13 +126,13 @@ bool GameLoader::load(MfcArchive &file) {
}
_gameName = file.readPascalString();
- debug(6, "_gameName: %s", _gameName);
+ debug(1, "_gameName: %s", _gameName);
_inventory.load(file);
_interactionController->load(file);
- debug(6, "sceneTag count: %d", _gameProject->_sceneTagList->size());
+ debug(1, "sceneTag count: %d", _gameProject->_sceneTagList->size());
_sc2array.resize(_gameProject->_sceneTagList->size());
@@ -142,7 +142,7 @@ bool GameLoader::load(MfcArchive &file) {
snprintf(tmp, 11, "%04d.sc2", it->_sceneId);
- debug(2, "sc: %s", tmp);
+ debug(1, "sc: %s", tmp);
_sc2array[i].loadFile((const char *)tmp);
}
@@ -152,6 +152,8 @@ bool GameLoader::load(MfcArchive &file) {
_field_FA = file.readUint16LE();
_field_F8 = file.readUint16LE();
+ debug(1, "_field_FA: %d\n_field_F8: %d", _field_FA, _field_F8);
+
_gameVar = (GameVar *)file.readClass();
return true;
diff --git a/engines/fullpipe/messagehandlers.cpp b/engines/fullpipe/messagehandlers.cpp
index 94754ad22a..4e791a3b27 100644
--- a/engines/fullpipe/messagehandlers.cpp
+++ b/engines/fullpipe/messagehandlers.cpp
@@ -775,13 +775,13 @@ int MovGraph_messageHandler(ExCommand *cmd) {
int top;
if (link) {
- MovGraphNode *node = link->_movGraphNode1;
+ MovGraphNode *node = link->_graphSrc;
double sq = (ani->_oy - node->_y) * (ani->_oy - node->_y) + (ani->_ox - node->_x) * (ani->_ox - node->_x);
int off = (node->_field_14 >> 16) & 0xFF;
- double off2 = ((link->_movGraphNode2->_field_14 >> 8) & 0xff) - off;
+ double off2 = ((link->_graphDst->_field_14 >> 8) & 0xff) - off;
- top = off + (int)(sqrt(sq) * off2 / link->_z);
+ top = off + (int)(sqrt(sq) * off2 / link->_length);
} else {
top = (gr->calcOffset(ani->_ox, ani->_oy)->_field_14 >> 8) & 0xff;
}
diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp
index 1a61cb742a..baea2e28bd 100644
--- a/engines/fullpipe/motion.cpp
+++ b/engines/fullpipe/motion.cpp
@@ -836,7 +836,7 @@ Common::Array<MovItem *> *MovGraph::getPaths(StaticANIObject *ani, int x, int y,
point.x = ani->_ox;
point.y = ani->_oy;
- if (!calcChunk(idx, ani->_ox, ani->_oy, &_items[idx]->movarr, 0))
+ if (!getHitPoint(idx, ani->_ox, ani->_oy, &_items[idx]->movarr, 0))
getNearestPoint(idx, &point, &_items[idx]->movarr);
_items[idx]->count = 0;
@@ -845,19 +845,19 @@ Common::Array<MovItem *> *MovGraph::getPaths(StaticANIObject *ani, int x, int y,
_items[idx]->movitems = 0;
int arrSize;
- Common::Array<MovArr *> *movarr = genMovArr(x, y, &arrSize, flag1, 0);
+ Common::Array<MovArr *> *movarr = getHitPoints(x, y, &arrSize, flag1, 0);
if (movarr) {
for (int i = 0; i < arrSize; i++) {
int sz;
- Common::Array<MovItem *> *movitems = calcMovItems(&_items[idx]->movarr, (*movarr)[i], &sz);
+ Common::Array<MovItem *> *movitems = getPaths(&_items[idx]->movarr, (*movarr)[i], &sz);
if (sz > 0) {
for (int j = 0; j < sz; j++)
_items[idx]->movitems->push_back(movitems[j]);
-
- delete movitems;
}
+
+ delete movitems;
}
delete movarr;
@@ -1008,7 +1008,7 @@ bool MovGraph::canDropInventory(StaticANIObject *ani, int x, int y) {
return true;
}
}
- } else if (calcChunk(idx, ani->_ox, ani->_oy, &m, 0) && m._link && (m._link->_flags & 0x4000000)) {
+ } else if (getHitPoint(idx, ani->_ox, ani->_oy, &m, 0) && m._link && (m._link->_flags & 0x4000000)) {
return true;
}
}
@@ -1074,7 +1074,7 @@ MessageQueue *MovGraph::doWalkTo(StaticANIObject *subj, int xpos, int ypos, int
_items[idx]->movarr._afield_8 = -1;
_items[idx]->movarr._link = 0;
- MessageQueue *mq = fillMGMinfo(_items[idx]->ani, &_items[idx]->movarr, staticsId);
+ MessageQueue *mq = makeWholeQueue(_items[idx]->ani, &_items[idx]->movarr, staticsId);
if (mq) {
ExCommand *ex = new ExCommand();
ex->_messageKind = 17;
@@ -1129,7 +1129,7 @@ MessageQueue *MovGraph::sub1(StaticANIObject *ani, int x, int y, int stid, int x
_items[idx]->movarr._afield_8 = -1;
_items[idx]->movarr._link = 0;
- res = fillMGMinfo(_items[idx]->ani, &_items[idx]->movarr, stid2);
+ res = makeWholeQueue(_items[idx]->ani, &_items[idx]->movarr, stid2);
break;
}
@@ -1140,7 +1140,7 @@ MessageQueue *MovGraph::sub1(StaticANIObject *ani, int x, int y, int stid, int x
return res;
}
-MessageQueue *MovGraph::fillMGMinfo(StaticANIObject *ani, MovArr *movarr, int staticsId) {
+MessageQueue *MovGraph::makeWholeQueue(StaticANIObject *ani, MovArr *movarr, int staticsId) {
if (!movarr->_movStepCount)
return 0;
@@ -1176,16 +1176,16 @@ MessageQueue *MovGraph::fillMGMinfo(StaticANIObject *ani, MovArr *movarr, int st
if (i == movarr->_movStepCount - 1) {
nx = movarr->_point.x;
ny = movarr->_point.y;
- nd = st->link->_movGraphNode1->_z;
+ nd = st->link->_graphSrc->_z;
} else {
if (st->sfield_0) {
- nx = st->link->_movGraphNode1->_x;
- ny = st->link->_movGraphNode1->_y;
- nd = st->link->_movGraphNode1->_z;
+ nx = st->link->_graphSrc->_x;
+ ny = st->link->_graphSrc->_y;
+ nd = st->link->_graphSrc->_z;
} else {
- nx = st->link->_movGraphNode2->_x;
- ny = st->link->_movGraphNode2->_y;
- nd = st->link->_movGraphNode2->_z;
+ nx = st->link->_graphDst->_x;
+ ny = st->link->_graphDst->_y;
+ nd = st->link->_graphDst->_z;
}
}
@@ -1261,7 +1261,7 @@ MessageQueue *MovGraph::method50(StaticANIObject *ani, MovArr *movarr, int stati
_items[idx]->movarr._afield_8 = -1;
_items[idx]->movarr._link = 0;
- MessageQueue *mq = fillMGMinfo(_items[idx]->ani, &_items[idx]->movarr, 0);
+ MessageQueue *mq = makeWholeQueue(_items[idx]->ani, &_items[idx]->movarr, 0);
if (!mq)
return 0;
@@ -1284,23 +1284,23 @@ MessageQueue *MovGraph::method50(StaticANIObject *ani, MovArr *movarr, int stati
}
double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int fuzzyMatch) {
- int n1x = link->_movGraphNode1->_x;
- int n1y = link->_movGraphNode1->_y;
- int n2x = link->_movGraphNode2->_x;
- int n2y = link->_movGraphNode2->_y;
+ int n1x = link->_graphSrc->_x;
+ int n1y = link->_graphSrc->_y;
+ int n2x = link->_graphDst->_x;
+ int n2y = link->_graphDst->_y;
double dist1x = (double)(point->x - n1x);
double dist1y = (double)(n1y - point->y);
double dist2x = (double)(n2x - n1x);
double dist2y = (double)(n2y - n1y);
double dist1 = sqrt(dist1y * dist1y + dist1x * dist1x);
- double dist2 = ((double)(n1y - n2y) * dist1y + dist2x * dist1x) / link->_z / dist1;
+ double dist2 = ((double)(n1y - n2y) * dist1y + dist2x * dist1x) / link->_length / dist1;
double distm = dist2 * dist1;
double res = sqrt(1.0 - dist2 * dist2) * dist1;
- if (dist2 <= 0.0 || distm >= link->_z) {
+ if (dist2 <= 0.0 || distm >= link->_length) {
if (fuzzyMatch) {
if (dist2 > 0.0) {
- if (distm >= link->_z) {
+ if (distm >= link->_length) {
point->x = n2x;
point->y = n2y;
}
@@ -1312,8 +1312,8 @@ double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int fuzz
return -1.0;
}
} else {
- point->x = (int)(n1x + (dist2x * distm / link->_z));
- point->y = (int)(n1y + (dist2y * distm / link->_z));
+ point->x = (int)(n1x + (dist2x * distm / link->_length));
+ point->y = (int)(n1y + (dist2y * distm / link->_length));
}
return res;
@@ -1340,14 +1340,14 @@ bool MovGraph::getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr)
MovGraphLink *lnk = (MovGraphLink *)*i;
if ((lnk->_flags & 0x10000000) && !(lnk->_flags & 0x20000000) ) {
- double dx1 = lnk->_movGraphNode1->_x - p->x;
- double dy1 = lnk->_movGraphNode1->_y - p->y;
- double dx2 = lnk->_movGraphNode2->_x - p->x;
- double dy2 = lnk->_movGraphNode2->_y - p->y;
- double dx3 = lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x;
- double dy3 = lnk->_movGraphNode2->_y - lnk->_movGraphNode1->_y;
+ double dx1 = lnk->_graphSrc->_x - p->x;
+ double dy1 = lnk->_graphSrc->_y - p->y;
+ double dx2 = lnk->_graphDst->_x - p->x;
+ double dy2 = lnk->_graphDst->_y - p->y;
+ double dx3 = lnk->_graphDst->_x - lnk->_graphSrc->_x;
+ double dy3 = lnk->_graphDst->_y - lnk->_graphSrc->_y;
double sq1 = sqrt(dy1 * dy1 + dx1 * dx1);
- double sdist = (dy3 * dy1 + dx3 * dx1) / lnk->_z / sq1;
+ double sdist = (dy3 * dy1 + dx3 * dx1) / lnk->_length / sq1;
double ldist = sdist * sq1;
double dist = sqrt(1.0 - sdist * sdist) * sq1;
@@ -1356,14 +1356,14 @@ bool MovGraph::getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr)
dist = sqrt(dx1 * dx1 + dy1 * dy1);
}
- if (ldist > lnk->_z) {
- ldist = lnk->_z;
+ if (ldist > lnk->_length) {
+ ldist = lnk->_length;
dist = sqrt(dx2 * dx2 + dy2 * dy2);
}
- if (ldist >= 0.0 && ldist <= lnk->_z && dist < mindist) {
- resx = lnk->_movGraphNode1->_x + (int)(dx3 * ldist / lnk->_z);
- resy = lnk->_movGraphNode1->_y + (int)(dy3 * ldist / lnk->_z);
+ if (ldist >= 0.0 && ldist <= lnk->_length && dist < mindist) {
+ resx = lnk->_graphSrc->_x + (int)(dx3 * ldist / lnk->_length);
+ resy = lnk->_graphSrc->_y + (int)(dy3 * ldist / lnk->_length);
mindist = dist;
link = lnk;
@@ -1394,7 +1394,7 @@ int MovGraph::getObjectIndex(StaticANIObject *ani) {
return -1;
}
-Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int flag1, int flag2) {
+Common::Array<MovArr *> *MovGraph::getHitPoints(int x, int y, int *arrSize, int flag1, int flag2) {
if (!_links.size()) {
*arrSize = 0;
@@ -1415,9 +1415,9 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla
movarr = new MovArr;
movarr->_link = lnk;
- movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - point.y) +
- (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(point.x - lnk->_movGraphNode1->_x)) /
- lnk->_z / lnk->_z;
+ movarr->_dist = ((double)(lnk->_graphSrc->_y - lnk->_graphDst->_y) * (double)(lnk->_graphSrc->_y - point.y) +
+ (double)(lnk->_graphDst->_x - lnk->_graphSrc->_x) * (double)(point.x - lnk->_graphSrc->_x)) /
+ lnk->_length / lnk->_length;
movarr->_point = point;
arr->push_back(movarr);
@@ -1430,23 +1430,23 @@ Common::Array<MovArr *> *MovGraph::genMovArr(int x, int y, int *arrSize, int fla
movarr = new MovArr;
movarr->_link = lnk;
movarr->_dist = 0.0;
- movarr->_point.x = lnk->_movGraphNode1->_x;
- movarr->_point.y = lnk->_movGraphNode1->_y;
+ movarr->_point.x = lnk->_graphSrc->_x;
+ movarr->_point.y = lnk->_graphSrc->_y;
arr->push_back(movarr);
movarr = new MovArr;
movarr->_link = lnk;
movarr->_dist = 1.0;
- movarr->_point.x = lnk->_movGraphNode1->_x;
- movarr->_point.y = lnk->_movGraphNode1->_y;
+ movarr->_point.x = lnk->_graphSrc->_x;
+ movarr->_point.y = lnk->_graphSrc->_y;
arr->push_back(movarr);
}
} else {
movarr = new MovArr;
movarr->_link = lnk;
- movarr->_dist = ((double)(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y) * (double)(lnk->_movGraphNode1->_y - y) +
- (double)(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) * (double)(x - lnk->_movGraphNode1->_x)) /
- lnk->_z / lnk->_z;
+ movarr->_dist = ((double)(lnk->_graphSrc->_y - lnk->_graphDst->_y) * (double)(lnk->_graphSrc->_y - y) +
+ (double)(lnk->_graphDst->_x - lnk->_graphSrc->_x) * (double)(x - lnk->_graphSrc->_x)) /
+ lnk->_length / lnk->_length;
movarr->_point.x = x;
movarr->_point.y = y;
@@ -1478,9 +1478,9 @@ void MovGraph::findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array
for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) {
MovGraphLink *l = (MovGraphLink *)*i;
- if (l->_movGraphNode1 != lnk->_movGraphNode1) {
- if (l->_movGraphNode2 != lnk->_movGraphNode1) {
- if (l->_movGraphNode1 != lnk->_movGraphNode2 && l->_movGraphNode2 != lnk->_movGraphNode2)
+ if (l->_graphSrc != lnk->_graphSrc) {
+ if (l->_graphDst != lnk->_graphSrc) {
+ if (l->_graphSrc != lnk->_graphDst && l->_graphDst != lnk->_graphDst)
continue;
}
}
@@ -1494,7 +1494,7 @@ void MovGraph::findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array
}
// Returns a list of possible paths two points in graph space
-Common::Array<MovItem *> *MovGraph::calcMovItems(MovArr *currPos, MovArr *destPos, int *pathCount) {
+Common::Array<MovItem *> *MovGraph::getPaths(MovArr *currPos, MovArr *destPos, int *pathCount) {
Common::Array<MovGraphLink *> tempObList1;
Common::Array<MovGraphLink *> allPaths;
@@ -1530,7 +1530,7 @@ void MovGraph::genMovItem(MovItem *movitem, MovGraphLink *grlink, MovArr *movarr
warning("STUB: MovGraph::genMovItem()");
}
-bool MovGraph::calcChunk(int idx, int x, int y, MovArr *arr, int a6) {
+bool MovGraph::getHitPoint(int idx, int x, int y, MovArr *arr, int a6) {
int staticsId;
if (_items[idx]->ani->_statics) {
@@ -1544,7 +1544,7 @@ bool MovGraph::calcChunk(int idx, int x, int y, MovArr *arr, int a6) {
int arrSize;
- Common::Array<MovArr *> *movarr = genMovArr(x, y, &arrSize, 0, 1);
+ Common::Array<MovArr *> *movarr = getHitPoints(x, y, &arrSize, 0, 1);
if (!movarr)
return getNearestPoint(idx, 0, arr);
@@ -1581,20 +1581,20 @@ bool MovGraph::calcChunk(int idx, int x, int y, MovArr *arr, int a6) {
}
void MovGraph::setEnds(MovStep *step1, MovStep *step2) {
- if (step1->link->_movGraphNode1 == step2->link->_movGraphNode2) {
+ if (step1->link->_graphSrc == step2->link->_graphDst) {
step1->sfield_0 = 1;
step2->sfield_0 = 1;
return;
}
- if (step1->link->_movGraphNode1 == step2->link->_movGraphNode1) {
+ if (step1->link->_graphSrc == step2->link->_graphSrc) {
step1->sfield_0 = 1;
step2->sfield_0 = 0;
} else {
step1->sfield_0 = 0;
- if (step1->link->_movGraphNode2 != step2->link->_movGraphNode1) {
+ if (step1->link->_graphDst != step2->link->_graphSrc) {
step2->sfield_0 = 1;
} else {
step2->sfield_0 = 0;
@@ -2241,7 +2241,7 @@ MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int
if (linkInfoSource.node)
movInfo1.distance1 = linkInfoSource.node->_z;
else
- movInfo1.distance1 = linkInfoSource.link->_movGraphNode1->_z;
+ movInfo1.distance1 = linkInfoSource.link->_graphSrc->_z;
if (linkInfoDest.node) {
dx2 = linkInfoDest.node->_x;
@@ -2255,11 +2255,11 @@ MessageQueue *MovGraph2::doWalkTo(StaticANIObject *obj, int xpos, int ypos, int
movInfo1.pt2.x = xpos;
movInfo1.pt2.y = ypos;
- MovGraphNode *nod = linkInfoDest.link->_movGraphNode1;
+ MovGraphNode *nod = linkInfoDest.link->_graphSrc;
double dst1 = sqrt((double)((ypos - nod->_y) * (ypos - nod->_y) + (xpos - nod->_x) * (xpos - nod->_x)));
- int dst = linkInfoDest.link->_movGraphNode2->_z - nod->_z;
+ int dst = linkInfoDest.link->_graphDst->_z - nod->_z;
- movInfo1.distance2 = (int)(nod->_z + (dst1 * (double)dst / linkInfoDest.link->_z));
+ movInfo1.distance2 = (int)(nod->_z + (dst1 * (double)dst / linkInfoDest.link->_length));
calcDistance(&movInfo1.pt2, linkInfoDest.link, 1);
@@ -2349,7 +2349,7 @@ int MovGraph2::getShortSide(MovGraphLink *lnk, int x, int y) {
bool cond;
if (lnk)
- cond = abs(lnk->_movGraphNode2->_x - lnk->_movGraphNode1->_x) > abs(lnk->_movGraphNode2->_y - lnk->_movGraphNode1->_y);
+ cond = abs(lnk->_graphDst->_x - lnk->_graphSrc->_x) > abs(lnk->_graphDst->_y - lnk->_graphSrc->_y);
else
cond = abs(x) > abs(y);
@@ -2360,16 +2360,16 @@ int MovGraph2::getShortSide(MovGraphLink *lnk, int x, int y) {
}
int MovGraph2::findLink(Common::Array<MovGraphLink *> *linkList, int idx, Common::Rect *rect, Common::Point *point) {
- MovGraphNode *node1 = (*linkList)[idx]->_movGraphNode1;
- MovGraphNode *node2 = (*linkList)[idx]->_movGraphNode2;
+ MovGraphNode *node1 = (*linkList)[idx]->_graphSrc;
+ MovGraphNode *node2 = (*linkList)[idx]->_graphDst;
MovGraphNode *node3 = node1;
if (idx != 0) {
MovGraphLink *lnk = (*linkList)[idx - 1];
- if (lnk->_movGraphNode2 != node1) {
- if (lnk->_movGraphNode1 != node1) {
- if (lnk->_movGraphNode2 == node2 || lnk->_movGraphNode1 == node2) {
+ if (lnk->_graphDst != node1) {
+ if (lnk->_graphSrc != node1) {
+ if (lnk->_graphDst == node2 || lnk->_graphSrc == node2) {
node3 = node2;
node2 = node1;
}
@@ -2380,10 +2380,10 @@ int MovGraph2::findLink(Common::Array<MovGraphLink *> *linkList, int idx, Common
} else if (idx != (int)(linkList->size() - 1)) {
MovGraphLink *lnk = (*linkList)[idx + 1];
- if (lnk->_movGraphNode2 == node1 || lnk->_movGraphNode1 == node1) {
+ if (lnk->_graphDst == node1 || lnk->_graphSrc == node1) {
node3 = node2;
node2 = node1;
- } else if (lnk->_movGraphNode2 == node2 || lnk->_movGraphNode1 == node2) {
+ } else if (lnk->_graphDst == node2 || lnk->_graphSrc == node2) {
node3 = node1;
}
}
@@ -2625,7 +2625,7 @@ MovGraphLink *MovGraph2::findLink1(int x, int y, int idx, int fuzzyMatch) {
return lnk;
} else if (!(lnk->_flags & 0x20000000)) {
if (lnk->_movGraphReact->pointInRegion(x, y)) {
- if (abs(lnk->_movGraphNode1->_x - lnk->_movGraphNode2->_x) <= abs(lnk->_movGraphNode1->_y - lnk->_movGraphNode2->_y)) {
+ if (abs(lnk->_graphSrc->_x - lnk->_graphDst->_x) <= abs(lnk->_graphSrc->_y - lnk->_graphDst->_y)) {
if (idx == 2 || idx == 3)
return lnk;
res = lnk;
@@ -2651,14 +2651,14 @@ MovGraphLink *MovGraph2::findLink2(int x, int y) {
MovGraphLink *lnk = (MovGraphLink *)*i;
if (!(lnk->_flags & 0x20000000)) {
- double n1x = lnk->_movGraphNode1->_x;
- double n1y = lnk->_movGraphNode1->_y;
- double n2x = lnk->_movGraphNode2->_x;
- double n2y = lnk->_movGraphNode2->_y;
+ double n1x = lnk->_graphSrc->_x;
+ double n1y = lnk->_graphSrc->_y;
+ double n2x = lnk->_graphDst->_x;
+ double n2y = lnk->_graphDst->_y;
double n1dx = n1x - x;
double n1dy = n1y - y;
double dst1 = sqrt(n1dy * n1dy + n1dx * n1dx);
- double coeff1 = ((n1y - n2y) * n1dy + (n2x - n1x) * n1dx) / lnk->_z / dst1;
+ double coeff1 = ((n1y - n2y) * n1dy + (n2x - n1x) * n1dx) / lnk->_length / dst1;
double dst3 = coeff1 * dst1;
double dst2 = sqrt(1.0 - coeff1 * coeff1) * dst1;
@@ -2666,11 +2666,11 @@ MovGraphLink *MovGraph2::findLink2(int x, int y) {
dst3 = 0.0;
dst2 = sqrt(n1dy * n1dy + n1dx * n1dx);
}
- if (dst3 > lnk->_z) {
- dst3 = lnk->_z;
+ if (dst3 > lnk->_length) {
+ dst3 = lnk->_length;
dst2 = sqrt((n2x - x) * (n2x - x) + (n2y - y) * (n2y - y));
}
- if (dst3 >= 0.0 && dst3 <= lnk->_z && dst2 < mindist) {
+ if (dst3 >= 0.0 && dst3 <= lnk->_length && dst2 < mindist) {
mindist = dst2;
res = lnk;
}
@@ -2693,7 +2693,7 @@ double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest,
for (ObList::iterator i = _links.begin(); i != _links.end(); ++i) {
MovGraphLink *lnk = (MovGraphLink *)*i;
- if ((lnk->_movGraphNode1 == linkInfoSource->node || lnk->_movGraphNode2 == linkInfoSource->node) && !(lnk->_flags & 0xA0000000)) {
+ if ((lnk->_graphSrc == linkInfoSource->node || lnk->_graphDst == linkInfoSource->node) && !(lnk->_flags & 0xA0000000)) {
linkInfoWorkSource.node = 0;
linkInfoWorkSource.link = lnk;
@@ -2703,18 +2703,18 @@ double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest,
double newDistance = findMinPath(&linkInfoWorkSource, linkInfoDest, &tmpList);
- if (newDistance >= 0.0 && (minDistance < 0.0 || newDistance + lnk->_z < minDistance)) {
+ if (newDistance >= 0.0 && (minDistance < 0.0 || newDistance + lnk->_length < minDistance)) {
listObj->clear();
listObj->push_back(tmpList);
- minDistance = newDistance + lnk->_z;
+ minDistance = newDistance + lnk->_length;
}
lnk->_flags &= 0x7FFFFFFF;
}
}
} else if (linkInfoSource->link) {
- linkInfoWorkSource.node = linkInfoSource->link->_movGraphNode1;
+ linkInfoWorkSource.node = linkInfoSource->link->_graphSrc;
linkInfoWorkSource.link = 0;
Common::Array<MovGraphLink *> tmpList;
@@ -2731,7 +2731,7 @@ double MovGraph2::findMinPath(LinkInfo *linkInfoSource, LinkInfo *linkInfoDest,
}
linkInfoWorkSource.link = 0;
- linkInfoWorkSource.node = linkInfoSource->link->_movGraphNode2;
+ linkInfoWorkSource.node = linkInfoSource->link->_graphDst;
tmpList.clear();
@@ -2774,11 +2774,11 @@ MovGraphNode *MovGraph::calcOffset(int ox, int oy) {
}
MovGraphLink::MovGraphLink() {
- _z = 0;
+ _length = 0;
_angle = 0;
_flags = 0x10000000;
- _movGraphNode2 = 0;
- _movGraphNode1 = 0;
+ _graphDst = 0;
+ _graphSrc = 0;
_field_3C = 0;
_field_38 = 0;
_movGraphReact = 0;
@@ -2804,14 +2804,14 @@ bool MovGraphLink::load(MfcArchive &file) {
_flags = file.readUint32LE();
debug(8, "GraphNode1");
- _movGraphNode1 = (MovGraphNode *)file.readClass();
+ _graphSrc = (MovGraphNode *)file.readClass();
debug(8, "GraphNode2");
- _movGraphNode2 = (MovGraphNode *)file.readClass();
+ _graphDst = (MovGraphNode *)file.readClass();
- _z = file.readDouble();
+ _length = file.readDouble();
_angle = file.readDouble();
- debug(8, "distance: %g, angle: %g", _z, _angle);
+ debug(8, "length: %g, angle: %g", _length, _angle);
_movGraphReact = (MovGraphReact *)file.readClass();
_name = file.readPascalString();
@@ -2820,11 +2820,11 @@ bool MovGraphLink::load(MfcArchive &file) {
}
void MovGraphLink::recalcLength() {
- if (_movGraphNode1) {
- double dx = _movGraphNode2->_x - _movGraphNode1->_x;
- double dy = _movGraphNode2->_y - _movGraphNode1->_y;
+ if (_graphSrc) {
+ double dx = _graphDst->_x - _graphSrc->_x;
+ double dy = _graphDst->_y - _graphSrc->_y;
- _z = sqrt(dy * dy + dx * dx);
+ _length = sqrt(dy * dy + dx * dx);
_angle = atan2(dx, dy);
}
}
diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h
index a40d810ffa..b8c3ff1f43 100644
--- a/engines/fullpipe/motion.h
+++ b/engines/fullpipe/motion.h
@@ -218,14 +218,14 @@ public:
class MovGraphLink : public CObject {
public:
- MovGraphNode *_movGraphNode1;
- MovGraphNode *_movGraphNode2;
+ MovGraphNode *_graphSrc;
+ MovGraphNode *_graphDst;
DWordArray _dwordArray1;
DWordArray _dwordArray2;
int _flags;
int _field_38;
int _field_3C;
- double _z;
+ double _length;
double _angle;
MovGraphReact *_movGraphReact;
char *_name;
@@ -307,13 +307,13 @@ public:
bool getNearestPoint(int unusedArg, Common::Point *p, MovArr *movarr);
MovGraphNode *calcOffset(int ox, int oy);
int getObjectIndex(StaticANIObject *ani);
- Common::Array<MovArr *> *genMovArr(int x, int y, int *arrSize, int flag1, int flag2);
+ Common::Array<MovArr *> *getHitPoints(int x, int y, int *arrSize, int flag1, int flag2);
void findAllPaths(MovGraphLink *lnk, MovGraphLink *lnk2, Common::Array<MovGraphLink *> &tempObList1, Common::Array<MovGraphLink *> &tempObList2);
- Common::Array<MovItem *> *calcMovItems(MovArr *movarr1, MovArr *movarr2, int *listCount);
+ Common::Array<MovItem *> *getPaths(MovArr *movarr1, MovArr *movarr2, int *listCount);
void genMovItem(MovItem *movitem, MovGraphLink *grlink, MovArr *movarr1, MovArr *movarr2);
- bool calcChunk(int idx, int x, int y, MovArr *arr, int a6);
+ bool getHitPoint(int idx, int x, int y, MovArr *arr, int a6);
MessageQueue *sub1(StaticANIObject *ani, int x, int y, int a5, int x1, int y1, int a8, int a9);
- MessageQueue *fillMGMinfo(StaticANIObject *ani, MovArr *movarr, int staticsId);
+ MessageQueue *makeWholeQueue(StaticANIObject *ani, MovArr *movarr, int staticsId);
void setEnds(MovStep *step1, MovStep *step2);
};
diff --git a/engines/fullpipe/scenes.h b/engines/fullpipe/scenes.h
index 0b7c4e7c8f..17ef5c3140 100644
--- a/engines/fullpipe/scenes.h
+++ b/engines/fullpipe/scenes.h
@@ -26,7 +26,7 @@
namespace Fullpipe {
struct Bat;
-struct BehaviorEntryInfo;
+struct BehaviorMove;
struct Hanger;
class MGM;
class MctlLadder;
@@ -346,12 +346,12 @@ public:
int scene06_sceneClickX;
int scene06_sceneClickY;
int scene06_mumsyPos;
- BehaviorEntryInfo *scene06_mumsyJumpBk;
- BehaviorEntryInfo *scene06_mumsyJumpFw;
+ BehaviorMove *scene06_mumsyJumpBk;
+ BehaviorMove *scene06_mumsyJumpFw;
int scene06_mumsyJumpBkPercent;
int scene06_mumsyJumpFwPercent;
- BehaviorEntryInfo *scene07_lukeAnim;
+ BehaviorMove *scene07_lukeAnim;
int scene07_lukePercent;
StaticANIObject *scene07_plusMinus;
diff --git a/engines/fullpipe/scenes/scene06.cpp b/engines/fullpipe/scenes/scene06.cpp
index e9cecc42f0..14042031bf 100644
--- a/engines/fullpipe/scenes/scene06.cpp
+++ b/engines/fullpipe/scenes/scene06.cpp
@@ -38,8 +38,8 @@
namespace Fullpipe {
void scene06_initMumsy() {
- g_vars->scene06_mumsyJumpFw = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene06_mumsy, ST_MOM_STANDS, QU_MOM_JUMPFW);
- g_vars->scene06_mumsyJumpBk = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene06_mumsy, ST_MOM_STANDS, QU_MOM_JUMPBK);
+ g_vars->scene06_mumsyJumpFw = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene06_mumsy, ST_MOM_STANDS, QU_MOM_JUMPFW);
+ g_vars->scene06_mumsyJumpBk = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene06_mumsy, ST_MOM_STANDS, QU_MOM_JUMPBK);
g_vars->scene06_mumsyJumpFwPercent = g_vars->scene06_mumsyJumpFw->_percent;
g_vars->scene06_mumsyJumpBkPercent = g_vars->scene06_mumsyJumpBk->_percent;
}
diff --git a/engines/fullpipe/scenes/scene07.cpp b/engines/fullpipe/scenes/scene07.cpp
index 6db8c30932..6f98d014bc 100644
--- a/engines/fullpipe/scenes/scene07.cpp
+++ b/engines/fullpipe/scenes/scene07.cpp
@@ -66,7 +66,7 @@ void sceneHandler07_openLuke() {
} else {
StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_CORNERSITTER, -1);
- g_vars->scene07_lukeAnim = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(ani, ST_CST_HANDLELESS, QU_CST_CLOSELUKE);
+ g_vars->scene07_lukeAnim = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(ani, ST_CST_HANDLELESS, QU_CST_CLOSELUKE);
g_vars->scene07_lukeAnim->_percent = g_vars->scene07_lukePercent;
}
@@ -78,7 +78,7 @@ void sceneHandler07_closeLuke() {
if (!g_vars->scene07_lukeAnim) {
StaticANIObject *ani = g_fp->_currentScene->getStaticANIObject1ById(ANI_CORNERSITTER, -1);
- g_vars->scene07_lukeAnim = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(ani, ST_CST_HANDLELESS, QU_CST_CLOSELUKE);
+ g_vars->scene07_lukeAnim = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(ani, ST_CST_HANDLELESS, QU_CST_CLOSELUKE);
}
g_vars->scene07_lukePercent = g_vars->scene07_lukeAnim->_percent;
diff --git a/engines/fullpipe/scenes/scene13.cpp b/engines/fullpipe/scenes/scene13.cpp
index c7b3c96b93..1397248bd5 100644
--- a/engines/fullpipe/scenes/scene13.cpp
+++ b/engines/fullpipe/scenes/scene13.cpp
@@ -178,14 +178,14 @@ void sceneHandler13_openFast() {
}
void sceneHandler13_uneatGum() {
- BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_CHEW);
+ BehaviorMove *beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_CHEW);
if (beh) {
beh->_percent = 0;
beh->_delay = 36;
}
- beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_PLUU);
+ beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_PLUU);
if (beh) {
beh->_percent = 0;
beh->_delay = 36;
@@ -193,7 +193,7 @@ void sceneHandler13_uneatGum() {
}
void sceneHandler13_eatGum() {
- BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_CHEW);
+ BehaviorMove *beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_CHEW);
if (beh) {
beh->_percent = 10922;
@@ -216,7 +216,7 @@ void sceneHandler13_showGum() {
chainQueue(QU_SC13_SHOWGUM, 0);
}
-void sceneHandler13_setBehFlag(BehaviorEntryInfo *beh, bool flag) {
+void sceneHandler13_setBehFlag(BehaviorMove *beh, bool flag) {
if (!flag) {
beh->_percent = 327;
beh->_flags |= 1;
@@ -229,11 +229,11 @@ void sceneHandler13_setBehFlag(BehaviorEntryInfo *beh, bool flag) {
}
void sceneHandler13_walkForward(bool flag) {
- BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_RTOL);
+ BehaviorMove *beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT, QU_STR_RTOL);
sceneHandler13_setBehFlag(beh, flag);
- beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_LEFT, QU_STR_TURNR);
+ beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_LEFT, QU_STR_TURNR);
sceneHandler13_setBehFlag(beh, flag);
@@ -241,11 +241,11 @@ void sceneHandler13_walkForward(bool flag) {
}
void sceneHandler13_walkBackward(bool flag) {
- BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT|0x4000, QU_STR_LTOR);
+ BehaviorMove *beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_RIGHT|0x4000, QU_STR_LTOR);
sceneHandler13_setBehFlag(beh, flag);
- beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene13_guard, ST_STR_LEFT|0x4000, QU_STR_TURNR_L);
+ beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene13_guard, ST_STR_LEFT|0x4000, QU_STR_TURNR_L);
sceneHandler13_setBehFlag(beh, flag);
diff --git a/engines/fullpipe/scenes/scene14.cpp b/engines/fullpipe/scenes/scene14.cpp
index dc919c6d7f..d3ba3c345e 100644
--- a/engines/fullpipe/scenes/scene14.cpp
+++ b/engines/fullpipe/scenes/scene14.cpp
@@ -266,8 +266,8 @@ void sceneHandler14_showBallFly() {
}
void sceneHandler14_grandmaJump() {
- BehaviorEntryInfo *beh1 = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_JUMPFW);
- BehaviorEntryInfo *beh2 = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_JUMPBK);
+ BehaviorMove *beh1 = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_JUMPFW);
+ BehaviorMove *beh2 = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_JUMPBK);
if (beh1) {
if (beh2) {
@@ -286,11 +286,11 @@ void sceneHandler14_endArcade() {
getGameLoaderInteractionController()->enableFlag24();
getCurrSceneSc2MotionController()->activate();
- BehaviorEntryInfo *beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_BLINK);
+ BehaviorMove *beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_BLINK);
if (beh)
beh->_percent = 327;
- beh = g_fp->_behaviorManager->getBehaviorEntryInfoByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_THROW);
+ beh = g_fp->_behaviorManager->getBehaviorMoveByMessageQueueDataId(g_vars->scene14_grandma, ST_GMA_SIT, QU_GMA_THROW);
if (beh)
beh->_percent = 0;
diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp
index 230d6c39a9..c82c2c414c 100644
--- a/engines/fullpipe/sound.cpp
+++ b/engines/fullpipe/sound.cpp
@@ -30,6 +30,7 @@
#include "fullpipe/statics.h"
#include "common/memstream.h"
+#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "audio/decoders/vorbis.h"
#include "audio/decoders/wave.h"
@@ -96,12 +97,13 @@ Sound::Sound() {
memset(_directSoundBuffers, 0, sizeof(_directSoundBuffers));
_description = 0;
_volume = 100;
+ _handle = new Audio::SoundHandle();
}
Sound::~Sound() {
freeSound();
-
free(_description);
+ delete _handle;
}
bool Sound::load(MfcArchive &file, NGIArchive *archive) {
@@ -206,14 +208,14 @@ void Sound::setPanAndVolumeByStaticAni() {
}
void Sound::setPanAndVolume(int vol, int pan) {
- g_fp->_mixer->setChannelVolume(_handle, vol / 39); // 0..10000
- g_fp->_mixer->setChannelBalance(_handle, pan / 78); // -10000..10000
+ g_fp->_mixer->setChannelVolume(*_handle, vol / 39); // 0..10000
+ g_fp->_mixer->setChannelBalance(*_handle, pan / 78); // -10000..10000
}
void Sound::play(int flag) {
- Audio::SoundHandle handle = getHandle();
+ Audio::SoundHandle *handle = getHandle();
- if (g_fp->_mixer->isSoundHandleActive(handle))
+ if (g_fp->_mixer->isSoundHandleActive(*handle))
return;
byte *soundData = loadData();
@@ -221,7 +223,7 @@ void Sound::play(int flag) {
Audio::RewindableAudioStream *wav = Audio::makeWAVStream(dataStream, DisposeAfterUse::YES);
Audio::AudioStream *audioStream = new Audio::LoopingAudioStream(wav, (flag == 1) ? 0 : 1);
- g_fp->_mixer->playStream(Audio::Mixer::kSFXSoundType, &handle, audioStream);
+ g_fp->_mixer->playStream(Audio::Mixer::kSFXSoundType, handle, audioStream);
}
void Sound::freeSound() {
@@ -231,11 +233,11 @@ void Sound::freeSound() {
}
int Sound::getVolume() {
- return g_fp->_mixer->getChannelVolume(_handle) * 39; // 0..10000
+ return g_fp->_mixer->getChannelVolume(*_handle) * 39; // 0..10000
}
void Sound::stop() {
- g_fp->_mixer->stopHandle(_handle);
+ g_fp->_mixer->stopHandle(*_handle);
}
void FullpipeEngine::setSceneMusicParameters(GameVar *gvar) {
@@ -353,7 +355,7 @@ void FullpipeEngine::startSoundStream1(char *trackName) {
stopAllSoundStreams();
#ifdef USE_VORBIS
- if (_mixer->isSoundHandleActive(_sceneTrackHandle))
+ if (_mixer->isSoundHandleActive(*_sceneTrackHandle))
return;
Common::File *track = new Common::File();
@@ -363,7 +365,7 @@ void FullpipeEngine::startSoundStream1(char *trackName) {
return;
}
Audio::RewindableAudioStream *ogg = Audio::makeVorbisStream(track, DisposeAfterUse::YES);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_sceneTrackHandle, ogg);
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _sceneTrackHandle, ogg);
#endif
}
diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h
index 14e766f5bb..983f28312b 100644
--- a/engines/fullpipe/sound.h
+++ b/engines/fullpipe/sound.h
@@ -23,6 +23,10 @@
#ifndef FULLPIPE_SOUND_H
#define FULLPIPE_SOUND_H
+namespace Audio {
+class SoundHandle;
+}
+
namespace Fullpipe {
class Sound : public MemoryObject {
@@ -31,7 +35,7 @@ class Sound : public MemoryObject {
int _directSoundBuffer;
int _directSoundBuffers[7];
byte *_soundData;
- Audio::SoundHandle _handle;
+ Audio::SoundHandle *_handle;
int _volume;
public:
@@ -45,7 +49,7 @@ public:
virtual bool load(MfcArchive &file) { assert(0); return false; } // Disable base class
void updateVolume();
int getId() const { return _id; }
- Audio::SoundHandle getHandle() const { return _handle; }
+ Audio::SoundHandle *getHandle() const { return _handle; }
void play(int flag);
void freeSound();
diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp
index 8ee3b14d0c..36fbb73037 100644
--- a/engines/fullpipe/statics.cpp
+++ b/engines/fullpipe/statics.cpp
@@ -1576,6 +1576,9 @@ Movement::Movement(Movement *src, int *oldIdxs, int newSize, StaticANIObject *an
_m2x = 0;
_m2y = 0;
+ _counter = 0;
+ _counterMax = 0;
+
_field_78 = 0;
_framePosOffsets = 0;
_field_84 = 0;
diff --git a/engines/game.cpp b/engines/game.cpp
index 85ad6fe2e8..7ff51a99cc 100644
--- a/engines/game.cpp
+++ b/engines/game.cpp
@@ -26,8 +26,8 @@
const PlainGameDescriptor *findPlainGameDescriptor(const char *gameid, const PlainGameDescriptor *list) {
const PlainGameDescriptor *g = list;
- while (g->gameid) {
- if (0 == scumm_stricmp(gameid, g->gameid))
+ while (g->gameId) {
+ if (0 == scumm_stricmp(gameid, g->gameId))
return g;
g++;
}
@@ -40,7 +40,7 @@ GameDescriptor::GameDescriptor() {
}
GameDescriptor::GameDescriptor(const PlainGameDescriptor &pgd, Common::String guioptions) {
- setVal("gameid", pgd.gameid);
+ setVal("gameid", pgd.gameId);
setVal("description", pgd.description);
if (!guioptions.empty())
diff --git a/engines/game.h b/engines/game.h
index a9bec8f9e0..e01e5c6885 100644
--- a/engines/game.h
+++ b/engines/game.h
@@ -36,7 +36,7 @@
* consisting of PlainGameDescriptors.
*/
struct PlainGameDescriptor {
- const char *gameid;
+ const char *gameId;
const char *description;
};
@@ -108,7 +108,7 @@ public:
GameList() {}
GameList(const GameList &list) : Common::Array<GameDescriptor>(list) {}
GameList(const PlainGameDescriptor *g) {
- while (g->gameid) {
+ while (g->gameId) {
push_back(GameDescriptor(*g));
g++;
}
diff --git a/engines/gnap/character.cpp b/engines/gnap/character.cpp
new file mode 100644
index 0000000000..56e520068d
--- /dev/null
+++ b/engines/gnap/character.cpp
@@ -0,0 +1,1405 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/character.h"
+#include "gnap/gamesys.h"
+
+namespace Gnap {
+
+Character::Character(GnapEngine *vm) : _vm(vm) {
+ _pos = Common::Point(0, 0);
+ _idleFacing = kDirIdleLeft;
+ _actionStatus = 0;
+ _sequenceId = 0;
+ _sequenceDatNum = 0;
+ _id = 0;
+ _gridX = 0;
+ _gridY = 0;
+
+ _walkNodesCount = 0;
+ _walkDestX = _walkDestY = 0;
+ _walkDeltaX = _walkDeltaY = 0;
+ _walkDirX = _walkDirY = 0;
+ _walkDirXIncr = _walkDirYIncr = 0;
+
+ for(int i = 0; i < kMaxGridStructs; i++) {
+ _walkNodes[i]._id = 0;
+ _walkNodes[i]._sequenceId = 0;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 0;
+ _walkNodes[i]._gridX1 = 0;
+ _walkNodes[i]._gridY1 = 0;
+ }
+}
+
+Character::~Character() {}
+
+void Character::walkStep() {
+ for (int i = 1; i < _vm->_gridMaxX; ++i) {
+ Common::Point checkPt = Common::Point(_pos.x + i, _pos.y);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - i, _pos.y);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x + 1, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - 1, _pos.y + 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x + 1, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+
+ checkPt = Common::Point(_pos.x - 1, _pos.y - 1);
+ if (!_vm->isPointBlocked(checkPt)) {
+ walkTo(checkPt, -1, -1, 1);
+ break;
+ }
+ }
+}
+/************************************************************************************************/
+
+PlayerGnap::PlayerGnap(GnapEngine * vm) : Character(vm) {
+ _brainPulseNum = 0;
+ _brainPulseRndValue = 0;
+}
+
+int PlayerGnap::getSequenceId(int kind, Common::Point gridPos) {
+ int sequenceId = 0;
+
+ switch (kind) {
+ case kGSPullOutDevice:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x83F;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x83D;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x83B;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x839;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x839;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x83B;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x83D;
+ break;
+ default:
+ sequenceId = 0x83F;
+ break;
+ }
+ }
+ break;
+
+ case kGSPullOutDeviceNonWorking:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x829;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x828;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x827;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x826;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x826;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x827;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x828;
+ break;
+ default:
+ sequenceId = 0x829;
+ break;
+ }
+ }
+ break;
+
+ case kGSScratchingHead:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x885;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x833;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x833;
+ _idleFacing = kDirBottomRight;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x885;
+ _idleFacing = kDirUpRight;
+ break;
+ default:
+ sequenceId = 0x834;
+ _idleFacing = kDirBottomLeft;
+ break;
+ }
+ }
+ break;
+
+ case kGSIdle:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x7BC;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x7BB;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x7BA;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7B9;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x7B9;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x7BA;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x7BB;
+ break;
+ default:
+ sequenceId = 0x7BC;
+ break;
+ }
+ }
+ break;
+
+ case kGSBrainPulsating:
+ _brainPulseNum = (_brainPulseNum + 1) & 1;
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
+ break;
+ case kDirBottomLeft:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
+ break;
+ case kDirUpRight:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
+ break;
+ default:
+ sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
+ break;
+ }
+ }
+ break;
+
+ case kGSImpossible:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7A8;
+ _idleFacing = kDirBottomRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ if (_pos.x % 2)
+ sequenceId = 0x7A8;
+ else
+ sequenceId = 0x89A;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x831;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ if (_vm->_currentSceneNum % 2)
+ sequenceId = 0x7A8;
+ else
+ sequenceId = 0x89A;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+
+ case kGSDeflect:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.y > gridPos.y) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x830;
+ _idleFacing = kDirUpLeft;
+ } else {
+ sequenceId = 0x82F;
+ _idleFacing = kDirUpRight;
+ }
+ } else {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x82E;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7A7;
+ _idleFacing = kDirBottomRight;
+ }
+ }
+ } else {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x7A7;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x82E;
+ break;
+ case kDirUpLeft:
+ sequenceId = 0x830;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x82F;
+ break;
+ case kDirIdleLeft:
+ case kDirIdleRight:
+ break;
+ }
+ }
+ break;
+
+ case kGSUseDevice:
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ sequenceId = 0x83A;
+ break;
+ case kDirBottomLeft:
+ sequenceId = 0x83C;
+ break;
+ case kDirUpLeft:
+ sequenceId = 0x840;
+ break;
+ case kDirUpRight:
+ sequenceId = 0x83E;
+ break;
+ case kDirIdleLeft:
+ case kDirIdleRight:
+ break;
+ }
+ break;
+
+ case kGSMoan1:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+
+ case kGSMoan2:
+ if (gridPos.x > 0 && gridPos.y > 0) {
+ if (_pos.x > gridPos.x) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ sequenceId = 0x832;
+ _idleFacing = kDirBottomLeft;
+ } else {
+ sequenceId = 0x7AA;
+ _idleFacing = kDirBottomRight;
+ }
+ break;
+ }
+
+ return sequenceId | 0x10000;
+}
+
+void PlayerGnap::useJointOnPlatypus() {
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->setGrabCursorSprite(-1);
+ if (doPlatypusAction(1, 0, 0x107C1, 0)) {
+ _actionStatus = 100;
+ _vm->_gameSys->setAnimation(0, 0, 1);
+ _vm->_gameSys->setAnimation(0x10876, plat._id, 0);
+ _vm->_gameSys->insertSequence(0x10875, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 15 * (5 * _pos.x - 30), 48 * (_pos.y - 7));
+ _sequenceDatNum = 1;
+ _sequenceId = 0x875;
+ _vm->_gameSys->insertSequence(0x10876, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 15 * (5 * plat._pos.x - 25), 48 * (plat._pos.y - 7));
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x876;
+ plat._idleFacing = kDirIdleLeft;
+ playSequence(0x107B5);
+ walkStep();
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ _actionStatus = -1;
+ } else {
+ playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000);
+ }
+}
+
+void PlayerGnap::kissPlatypus(int callback) {
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (doPlatypusAction(-1, 0, 0x107D1, callback)) {
+ _actionStatus = 100;
+ _vm->_gameSys->setAnimation(0, 0, 1);
+ _vm->_gameSys->setAnimation(0x10847, _id, 0);
+ _vm->_gameSys->insertSequence(0x10847, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 15 * (5 * _pos.x - 20) - (21 - _vm->_gridMinX), 48 * (_pos.y - 6) - (146 - _vm->_gridMinY));
+ _sequenceDatNum = 1;
+ _sequenceId = 0x847;
+ _vm->_gameSys->insertSequence(0x107CB, plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x10847), 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x7CB;
+ plat._idleFacing = kDirIdleLeft;
+ playSequence(0x107B5);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ _actionStatus = -1;
+ } else {
+ playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000);
+ }
+}
+
+void PlayerGnap::useDeviceOnPlatypus() {
+ PlayerPlat& plat = *_vm->_plat;
+
+ playSequence(makeRid(1, getSequenceId(kGSPullOutDevice, plat._pos)));
+
+ if (plat._idleFacing != kDirIdleLeft) {
+ _vm->_gameSys->insertSequence(makeRid(1, 0x7D5), plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceId = 0x7D5;
+ plat._sequenceDatNum = 1;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(1, 0x7D4), plat._id,
+ makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ plat._sequenceId = 0x7D4;
+ plat._sequenceDatNum = 1;
+ }
+
+ int newSequenceId = getSequenceId(kGSUseDevice, Common::Point(0, 0));
+ _vm->_gameSys->insertSequence(makeRid(1, newSequenceId), _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = newSequenceId;
+ _sequenceDatNum = 1;
+}
+
+void PlayerGnap::initBrainPulseRndValue() {
+ _brainPulseRndValue = 2 * _vm->getRandom(10);
+}
+
+void PlayerGnap::playSequence(int sequenceId) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ idle();
+ _vm->_gameSys->insertSequence(sequenceId, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+}
+
+void PlayerGnap::updateIdleSequence() {
+ if (_actionStatus < 0) {
+ if (_vm->_timers[2] > 0) {
+ if (_vm->_timers[3] == 0) {
+ _vm->_timers[2] = 60;
+ _vm->_timers[3] = 300;
+ if (_idleFacing == kDirBottomRight) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ playSequence(0x107A6);
+ break;
+ case 1:
+ playSequence(0x107AA);
+ break;
+ case 2:
+ playSequence(0x10841);
+ break;
+ default:
+ playSequence(0x108A2);
+ break;
+ }
+ } else if (_idleFacing == kDirBottomLeft) {
+ if (_vm->getRandom(5) > 2)
+ playSequence(0x10832);
+ else
+ playSequence(0x10842);
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ if (_idleFacing == kDirBottomRight) {
+ _vm->_gameSys->insertSequence(0x107BD, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BD;
+ _sequenceDatNum = 1;
+ } else if (_idleFacing == kDirBottomLeft) {
+ _vm->_gameSys->insertSequence(0x107BE, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BE;
+ _sequenceDatNum = 1;
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ }
+}
+
+void PlayerGnap::updateIdleSequence2() {
+ if (_actionStatus < 0) {
+ if (_vm->_timers[2] > 0) {
+ if (_vm->_timers[3] == 0) {
+ _vm->_timers[2] = 60;
+ _vm->_timers[3] = 300;
+ if (_idleFacing == kDirBottomRight) {
+ playSequence(0x107AA);
+ } else if (_idleFacing == kDirBottomLeft) {
+ playSequence(0x10832);
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ if (_idleFacing == kDirBottomRight) {
+ _vm->_gameSys->insertSequence(0x107BD, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BD;
+ _sequenceDatNum = 1;
+ } else if (_idleFacing == kDirBottomLeft) {
+ _vm->_gameSys->insertSequence(0x107BE, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = 0x7BE;
+ _sequenceDatNum = 1;
+ }
+ }
+ } else {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ }
+}
+
+void PlayerGnap::initPos(int gridX, int gridY, Facing facing) {
+ _vm->_timers[2] = 30;
+ _vm->_timers[3] = 300;
+ _pos = Common::Point(gridX, gridY);
+ if (facing == kDirIdleLeft)
+ _idleFacing = kDirBottomRight;
+ else
+ _idleFacing = facing;
+
+ if (_idleFacing == kDirBottomLeft) {
+ _sequenceId = 0x7B8;
+ } else {
+ _sequenceId = 0x7B5;
+ _idleFacing = kDirBottomRight;
+ }
+ _id = 20 * _pos.y;
+ _sequenceDatNum = 1;
+ _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
+ 0, 0,
+ kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+}
+
+int PlayerGnap::getWalkSequenceId(int deltaX, int deltaY) {
+ static const int walkSequenceIds[9] = {
+ 0x7B2, 0x000, 0x7B4,
+ 0x7AD, 0x000, 0x7AE,
+ 0x7B1, 0x000, 0x7B3
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert(id >= 0 && id < 9);
+
+ return walkSequenceIds[id];
+}
+
+bool PlayerGnap::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) {
+ PlayerPlat& plat = *_vm->_plat;
+ int datNum = flags & 3;
+
+ _vm->_timers[2] = 200;
+ _vm->_timers[3] = 300;
+
+ int gridX = gridPos.x;
+ if (gridX < 0)
+ gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ int gridY = gridPos.y;
+ if (gridY < 0)
+ gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48;
+
+ _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1);
+ _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1);
+
+ if (animationIndex >= 0 && _walkDestX == plat._pos.x && _walkDestY == plat._pos.y)
+ plat.makeRoom();
+
+ bool done = findPath1(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath2(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath3(_pos.x, _pos.y);
+
+ if (!done)
+ done = findPath4(_pos.x, _pos.y);
+
+ idle();
+
+ int gnapSequenceId = _sequenceId;
+ int gnapId = _id;
+ int gnapSequenceDatNum = _sequenceDatNum;
+
+ debugC(kDebugBasic, "_gnap->_walkNodesCount: %d", _walkNodesCount);
+
+ for (int index = 0; index < _walkNodesCount; ++index) {
+ _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1;
+ if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AB), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AB;
+ gnapSequenceId = 0x7AB;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AC), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AC;
+ gnapSequenceId = 0x7AC;
+ }
+ } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AF), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7AF;
+ gnapSequenceId = 0x7AF;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7B0), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7B0;
+ gnapSequenceId = 0x7B0;
+ }
+ } else {
+ if (_walkNodes[index]._deltaY == -1)
+ _walkNodes[index]._id -= 10;
+ else
+ _walkNodes[index]._id += 10;
+ int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY);
+ _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = newSequenceId;
+ gnapSequenceId = newSequenceId;
+ }
+ gnapId = _walkNodes[index]._id;
+ gnapSequenceDatNum = datNum;
+ }
+
+ if (flags & 8) {
+ if (_walkNodesCount > 0) {
+ _sequenceId = gnapSequenceId;
+ _id = gnapId;
+ _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ _sequenceDatNum = datNum;
+ if (animationIndex >= 0)
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex);
+ } else if (animationIndex >= 0) {
+ _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex);
+ _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ if (sequenceId >= 0 && sequenceId != -1) {
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+ if (_sequenceId == 0x7B9) {
+ _idleFacing = kDirBottomRight;
+ } else {
+ switch (_sequenceId) {
+ case 0x7BA:
+ _idleFacing = kDirBottomLeft;
+ break;
+ case 0x7BB:
+ _idleFacing = kDirUpRight;
+ break;
+ case 0x7BC:
+ _idleFacing = kDirUpLeft;
+ break;
+ }
+ }
+ } else {
+ if (_walkNodesCount > 0) {
+ _sequenceId = getWalkStopSequenceId(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY);
+ } else if (gridX >= 0 || gridY >= 0) {
+ switch (_idleFacing) {
+ case kDirBottomRight:
+ _sequenceId = 0x7B9;
+ break;
+ case kDirBottomLeft:
+ _sequenceId = 0x7BA;
+ break;
+ case kDirUpRight:
+ _sequenceId = 0x7BB;
+ break;
+ default:
+ _sequenceId = 0x7BC;
+ break;
+ }
+ } else {
+ int dirX = _vm->_leftClickMouseX - (_vm->_gridMinX + 75 * _pos.x);
+ int dirY = _vm->_leftClickMouseY - (_vm->_gridMinY + 48 * _pos.y);
+ if (dirX == 0)
+ dirX = 1;
+ if (dirY == 0)
+ dirY = 1;
+ _sequenceId = getWalkStopSequenceId(dirX / abs(dirX), dirY / abs(dirY));
+ _idleFacing = getWalkFacing(dirX / abs(dirX), dirY / abs(dirY));
+ }
+ _sequenceDatNum = datNum;
+ }
+
+ if (animationIndex < 0) {
+ _id = 20 * _walkDestY + 1;
+ } else {
+ _id = _walkNodesCount + animationIndex + 20 * _walkDestY;
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _walkNodesCount + animationIndex + 20 * _walkDestY, animationIndex);
+ }
+
+ if (flags & 4) {
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 0, 0);
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY);
+ }
+ }
+
+ _pos = Common::Point(_walkDestX, _walkDestY);
+
+ return done;
+}
+
+int PlayerGnap::getShowSequenceId(int index, int gridX, int gridY) {
+ int sequenceId;
+ Facing facing = _idleFacing;
+
+ if (gridY > 0 && gridX > 0) {
+ if (_pos.x > gridX)
+ _idleFacing = kDirUpLeft;
+ else
+ _idleFacing = kDirUpRight;
+ } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
+ _idleFacing = kDirUpLeft;
+ } else {
+ _idleFacing = kDirUpRight;
+ }
+
+ switch (index) {
+ case 0:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x8A0;
+ else
+ sequenceId = 0x8A1;
+ break;
+ case 1:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x880;
+ else
+ sequenceId = 0x895;
+ break;
+ case 2:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x884;
+ else
+ sequenceId = 0x899;
+ break;
+ //Skip 3
+ case 4:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x881;
+ else
+ sequenceId = 0x896;
+ break;
+ case 5:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x883;
+ else
+ sequenceId = 0x898;
+ break;
+ case 6:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87E;
+ else
+ sequenceId = 0x893;
+ break;
+ case 7:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x848;
+ else
+ sequenceId = 0x890;
+ break;
+ case 8:
+ case 12:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87D;
+ else
+ sequenceId = 0x892;
+ break;
+ case 9:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x882;
+ else
+ sequenceId = 0x897;
+ break;
+ case 10:
+ case 11:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87C;
+ else
+ sequenceId = 0x891;
+ break;
+ case 13:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x888;
+ else
+ sequenceId = 0x89D;
+ break;
+ case 14:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87F;
+ else
+ sequenceId = 0x894;
+ break;
+ case 15:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87B;
+ else
+ sequenceId = 0x8A3;
+ break;
+ case 16:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x877;
+ else
+ sequenceId = 0x88C;
+ break;
+ //Skip 17
+ case 18:
+ sequenceId = 0x887;
+ break;
+ case 19:
+ case 25:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x87A;
+ else
+ sequenceId = 0x88F;
+ break;
+ case 20:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x878;
+ else
+ sequenceId = 0x88D;
+ break;
+ case 21:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x879;
+ else
+ sequenceId = 0x88E;
+ break;
+ case 22:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x88A;
+ else
+ sequenceId = 0x89F;
+ break;
+ case 23:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x889;
+ else
+ sequenceId = 0x89E;
+ break;
+ case 24:
+ if (_idleFacing == kDirUpRight)
+ sequenceId = 0x886;
+ else
+ sequenceId = 0x89B;
+ break;
+ //Skip 26
+ //Skip 27
+ //Skip 28
+ //Skip 29
+ default:
+ _idleFacing = facing;
+ sequenceId = getSequenceId(kGSImpossible, Common::Point(0, 0));
+ break;
+ }
+
+ return sequenceId;
+}
+
+void PlayerGnap::idle() {
+ if (_sequenceDatNum == 1 &&
+ (_sequenceId == 0x7A6 || _sequenceId == 0x7AA ||
+ _sequenceId == 0x832 || _sequenceId == 0x841 ||
+ _sequenceId == 0x842 || _sequenceId == 0x8A2 ||
+ _sequenceId == 0x833 || _sequenceId == 0x834 ||
+ _sequenceId == 0x885 || _sequenceId == 0x7A8 ||
+ _sequenceId == 0x831 || _sequenceId == 0x89A)) {
+ _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0));
+ _sequenceDatNum = 1;
+ }
+}
+
+void PlayerGnap::actionIdle(int sequenceId) {
+ if (_sequenceId != -1 && ridToDatIndex(sequenceId) == _sequenceDatNum && ridToEntryIndex(sequenceId) == _sequenceId) {
+ _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0));
+ _sequenceDatNum = 1;
+ }
+}
+
+void PlayerGnap::playImpossible(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSImpossible, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playScratchingHead(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSScratchingHead, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playMoan1(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSMoan1, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playMoan2(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSMoan2, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playBrainPulsating(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSBrainPulsating, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playPullOutDevice(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSPullOutDevice, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playPullOutDeviceNonWorking(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSPullOutDeviceNonWorking, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playUseDevice(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSUseDevice, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playIdle(Common::Point gridPos) {
+ playSequence(getSequenceId(kGSIdle, gridPos) | 0x10000);
+}
+
+void PlayerGnap::playShowItem(int itemIndex, int gridLookX, int gridLookY) {
+ playSequence(getShowSequenceId(itemIndex, gridLookX, gridLookY) | 0x10000);
+}
+
+void PlayerGnap::playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY) {
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (plat._pos == destPos)
+ plat.makeRoom();
+ walkTo(destPos, -1, -1, 1);
+ playShowItem(_vm->_grabCursorSpriteIndex, gridLookX, gridLookY);
+}
+
+bool PlayerGnap::doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback) {
+ PlayerPlat& plat = *_vm->_plat;
+ bool result = false;
+
+ if (_actionStatus <= -1 && plat._actionStatus <= -1) {
+ _actionStatus = 100;
+ Common::Point checkPt = plat._pos + Common::Point(gridX, gridY);
+ if (_vm->isPointBlocked(checkPt) && (_pos != checkPt)) {
+ plat.walkStep();
+ checkPt = plat._pos + Common::Point(gridX, gridY);
+ }
+
+ if (!_vm->isPointBlocked(checkPt) && (_pos != checkPt)) {
+ walkTo(checkPt, 0, 0x107B9, 1);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ if (_pos == plat._pos + Common::Point(gridX, gridY)) {
+ _vm->_gameSys->setAnimation(platSequenceId, plat._id, 1);
+ plat.playSequence(platSequenceId);
+ while (_vm->_gameSys->getAnimationStatus(1) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->doCallback(callback);
+ _vm->gameUpdateTick();
+ }
+ result = true;
+ }
+ }
+ _actionStatus = -1;
+ }
+ return result;
+}
+
+void PlayerGnap::useDisguiseOnPlatypus() {
+ _vm->_gameSys->setAnimation(0x10846, _id, 0);
+ playSequence(0x10846);
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_newSceneNum = 47;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ _vm->setFlag(kGFPlatypusDisguised);
+}
+
+/************************************************************************************************/
+
+PlayerPlat::PlayerPlat(GnapEngine * vm) : Character(vm) {}
+
+int PlayerPlat::getSequenceId(int kind, Common::Point gridPos) {
+ // The original had 3 parameters, all always set to 0.
+ // The code to handle the other values has been removed.
+
+ int sequenceId = 0x7CB;
+
+ if (_idleFacing != kDirIdleLeft) {
+ sequenceId = 0x7CC;
+ _idleFacing = kDirIdleRight;
+ }
+
+ return sequenceId | 0x10000;
+}
+
+void PlayerPlat::playSequence(int sequenceId) {
+ _vm->_gameSys->insertSequence(sequenceId, _id,
+ makeRid(_sequenceDatNum, _sequenceId), _id,
+ kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+}
+
+void PlayerPlat::updateIdleSequence() {
+ if (_actionStatus < 0 && _vm->_gnap->_actionStatus < 0) {
+ if (_vm->_timers[0] > 0) {
+ if (_vm->_timers[1] == 0) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ int rnd = _vm->getRandom(10);
+ if (_idleFacing != kDirIdleLeft) {
+ if (rnd != 0 || _sequenceId != 0x7CA) {
+ if (rnd != 1 || _sequenceId != 0x7CA)
+ playSequence(0x107CA);
+ else
+ playSequence(0x10845);
+ } else {
+ playSequence(0x107CC);
+ }
+ } else if (rnd != 0 || _sequenceId != 0x7C9) {
+ if (rnd != 1 || _sequenceId != 0x7C9) {
+ if (rnd != 2 || _sequenceId != 0x7C9)
+ playSequence(0x107C9);
+ else
+ playSequence(0x108A4);
+ } else {
+ playSequence(0x10844);
+ }
+ } else {
+ playSequence(0x107CB);
+ }
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+}
+
+void PlayerPlat::updateIdleSequence2() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (_actionStatus < 0 && gnap._actionStatus < 0) {
+ if (_vm->_timers[0]) {
+ if (!_vm->_timers[1]) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ if (_idleFacing != kDirIdleLeft) {
+ if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7CA)
+ playSequence(0x107CA);
+ else
+ playSequence(0x107CC);
+ } else {
+ if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7C9) {
+ playSequence(0x107C9);
+ } else {
+ playSequence(0x107CB);
+ }
+ }
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+}
+
+void PlayerPlat::initPos(int gridX, int gridY, Facing facing) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[1] = 20;
+ _pos = Common::Point(gridX, gridY);
+ if (facing == kDirIdleLeft)
+ _idleFacing = kDirIdleLeft;
+ else
+ _idleFacing = facing;
+ if (_idleFacing == kDirIdleRight) {
+ _sequenceId = 0x7D1;
+ } else {
+ _sequenceId = 0x7C1;
+ _idleFacing = kDirIdleLeft;
+ }
+ _id = 20 * _pos.y;
+ _sequenceDatNum = 1;
+ _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
+ 0, 0,
+ kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
+}
+
+int PlayerPlat::getWalkSequenceId(int deltaX, int deltaY) {
+ static const int walkSequenceIds[9] = {
+ 0x7C5, 0x000, 0x7C8,
+ 0x7C4, 0x000, 0x7C7,
+ 0x7C3, 0x000, 0x7C6
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert(id >= 0 && id < 9);
+
+ return walkSequenceIds[id];
+}
+
+bool PlayerPlat::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) {
+ // Note: flags is always 1. The code could be simplified.
+
+ int datNum = flags & 3;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _vm->_timers[1] = 60;
+
+ int gridX = gridPos.x;
+ if (gridX < 0)
+ gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ int gridY = gridPos.y;
+ if (gridY < 0)
+ gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48;
+
+ _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1);
+ _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1);
+
+ if (animationIndex >= 0 && gnap._pos == Common::Point(_walkDestX, _walkDestY))
+ gnap.walkStep();
+
+ bool done = findPath1(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath2(_pos.x, _pos.y, 0);
+
+ if (!done)
+ done = findPath3(_pos.x, _pos.y);
+
+ if (!done)
+ done = findPath4(_pos.x, _pos.y);
+
+ int platSequenceId = _sequenceId;
+ int platId = _id;
+ int platSequenceDatNum = _sequenceDatNum;
+
+ for (int index = 0; index < _walkNodesCount; ++index) {
+ _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1;
+ if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CD), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CD;
+ platSequenceId = 0x7CD;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CE), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CE;
+ platSequenceId = 0x7CE;
+ }
+ } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) {
+ if (index % 2) {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CF), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7CF;
+ platSequenceId = 0x7CF;
+ } else {
+ _vm->_gameSys->insertSequence(makeRid(datNum, 0x7D0), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = 0x7D0;
+ platSequenceId = 0x7D0;
+ }
+ } else {
+ if (_walkNodes[index]._deltaY == -1)
+ _walkNodes[index]._id -= 10;
+ else
+ _walkNodes[index]._id += 10;
+ int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY);
+ _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY);
+ _walkNodes[index]._sequenceId = newSequenceId;
+ platSequenceId = newSequenceId;
+ }
+ platId = _walkNodes[index]._id;
+ platSequenceDatNum = datNum;
+ }
+
+ if (flags & 8) {
+ if (_walkNodesCount > 0) {
+ _sequenceId = platSequenceId;
+ _id = platId;
+ _sequenceDatNum = datNum;
+ if (_walkNodes[_walkNodesCount - 1]._deltaX > 0)
+ _idleFacing = kDirIdleLeft;
+ else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0)
+ _idleFacing = kDirIdleRight;
+ else if (_walkNodes[_walkNodesCount - 1]._gridX1 % 2)
+ _idleFacing = kDirIdleRight;
+ else
+ _idleFacing = kDirIdleLeft;
+ if (animationIndex >= 0)
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex);
+ } else if (animationIndex >= 0) {
+ _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex);
+ _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ if (sequenceId >= 0 && sequenceId != -1) {
+ _sequenceId = ridToEntryIndex(sequenceId);
+ _sequenceDatNum = ridToDatIndex(sequenceId);
+ if (_sequenceId == 0x7C2) {
+ _idleFacing = kDirIdleLeft;
+ } else if (_sequenceId == 0x7D2) {
+ _idleFacing = kDirIdleRight;
+ }
+ } else {
+ if (_walkNodesCount > 0) {
+ if (_walkNodes[_walkNodesCount - 1]._deltaX > 0) {
+ _sequenceId = 0x7C2;
+ _idleFacing = kDirIdleLeft;
+ } else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0) {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ } else if (_walkNodes[0]._deltaX > 0) {
+ _sequenceId = 0x7C2;
+ _idleFacing = kDirIdleLeft;
+ } else if (_walkNodes[0]._deltaX < 0) {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ } else {
+ _sequenceId = 0x7D2;
+ _idleFacing = kDirIdleRight;
+ }
+ } else if (_idleFacing != kDirIdleLeft) {
+ _sequenceId = 0x7D2;
+ } else {
+ _sequenceId = 0x7C2;
+ }
+ _sequenceDatNum = datNum;
+ }
+
+ if (animationIndex < 0) {
+ _id = 20 * _walkDestY;
+ } else {
+ _id = animationIndex + 20 * _walkDestY;
+ _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), animationIndex + 20 * _walkDestY, animationIndex);
+ }
+
+ if (flags & 4)
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ 9, 0, 0, 0);
+ else
+ _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id,
+ makeRid(platSequenceDatNum, platSequenceId), platId,
+ 9, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY);
+ }
+
+ _pos = Common::Point(_walkDestX, _walkDestY);
+
+ return done;
+}
+} // End of namespace Gnap
diff --git a/engines/gnap/character.h b/engines/gnap/character.h
new file mode 100644
index 0000000000..27e98be15c
--- /dev/null
+++ b/engines/gnap/character.h
@@ -0,0 +1,146 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_CHARACTER_H
+#define GNAP_CHARACTER_H
+
+namespace Gnap {
+
+class GnapEngine;
+
+enum Facing {
+ kDirIdleLeft = 0,
+ kDirBottomRight = 1,
+ kDirBottomLeft = 3,
+ kDirIdleRight = 4,
+ kDirUpLeft = 5,
+ kDirUpRight = 7
+};
+
+struct GridStruct {
+ int _deltaX, _deltaY;
+ int _gridX1, _gridY1;
+ int _sequenceId;
+ int _id;
+};
+
+const int kMaxGridStructs = 30;
+
+class Character {
+public:
+ Character(GnapEngine *vm);
+ virtual ~Character();
+
+ void walkStep();
+
+ virtual int getSequenceId(int kind, Common::Point gridPos) = 0;
+ virtual void playSequence(int sequenceId) = 0;
+ virtual void updateIdleSequence() = 0;
+ virtual void updateIdleSequence2() = 0;
+ virtual void initPos(int gridX, int gridY, Facing facing) = 0;
+ virtual int getWalkSequenceId(int deltaX, int deltaY) = 0;
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) = 0;
+
+ Common::Point _pos;
+ Facing _idleFacing;
+ int _actionStatus;
+ int _sequenceId;
+ int _sequenceDatNum;
+ int _id;
+ int _gridX;
+ int _gridY;
+ int _walkNodesCount;
+ GridStruct _walkNodes[kMaxGridStructs];
+ int _walkDestX, _walkDestY;
+ int _walkDeltaX, _walkDeltaY, _walkDirX, _walkDirY, _walkDirXIncr, _walkDirYIncr;
+
+protected:
+ GnapEngine *_vm;
+};
+
+class PlayerGnap : public Character {
+public:
+ PlayerGnap(GnapEngine *vm);
+ virtual int getSequenceId(int kind, Common::Point gridPos);
+ virtual void initPos(int gridX, int gridY, Facing facing);
+ virtual void playSequence(int sequenceId);
+ virtual void updateIdleSequence();
+ virtual void updateIdleSequence2();
+ virtual int getWalkSequenceId(int deltaX, int deltaY);
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags);
+
+ void actionIdle(int sequenceId);
+ bool doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback);
+ int getShowSequenceId(int index, int gridX, int gridY);
+ Facing getWalkFacing(int deltaX, int deltaY);
+ int getWalkStopSequenceId(int deltaX, int deltaY);
+ void idle();
+ void initBrainPulseRndValue();
+ void kissPlatypus(int callback);
+ void playBrainPulsating(Common::Point gridPos = Common::Point(0, 0));
+ void playIdle(Common::Point gridPos = Common::Point(0, 0));
+ void playImpossible(Common::Point gridPos = Common::Point(0, 0));
+ void playMoan1(Common::Point gridPos = Common::Point(0, 0));
+ void playMoan2(Common::Point gridPos = Common::Point(0, 0));
+ void playPullOutDevice(Common::Point gridPos = Common::Point(0, 0));
+ void playPullOutDeviceNonWorking(Common::Point gridPos = Common::Point(0, 0));
+ void playScratchingHead(Common::Point gridPos = Common::Point(0, 0));
+ void playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY);
+ void playShowItem(int itemIndex, int gridLookX, int gridLookY);
+ void playUseDevice(Common::Point gridPos = Common::Point(0, 0));
+ void useDeviceOnPlatypus();
+ void useDisguiseOnPlatypus();
+ void useJointOnPlatypus();
+
+ int _brainPulseNum;
+ int _brainPulseRndValue;
+
+private:
+ bool findPath1(int gridX, int gridY, int index);
+ bool findPath2(int gridX, int gridY, int index);
+ bool findPath3(int gridX, int gridY);
+ bool findPath4(int gridX, int gridY);
+};
+
+class PlayerPlat : public Character {
+public:
+ PlayerPlat(GnapEngine *vm);
+ virtual ~PlayerPlat() {}
+ virtual int getSequenceId(int kind = 0, Common::Point gridPos = Common::Point(0, 0));
+ virtual void initPos(int gridX, int gridY, Facing facing);
+ virtual void playSequence(int sequenceId);
+ virtual void updateIdleSequence();
+ virtual void updateIdleSequence2();
+ virtual int getWalkSequenceId(int deltaX, int deltaY);
+ virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags);
+
+ void makeRoom();
+
+private:
+ bool findPath1(int gridX, int gridY, int index);
+ bool findPath2(int gridX, int gridY, int index);
+ bool findPath3(int gridX, int gridY);
+ bool findPath4(int gridX, int gridY);
+};
+} // End of namespace Gnap
+
+#endif // GNAP_CHARACTER_H
diff --git a/engines/gnap/configure.engine b/engines/gnap/configure.engine
new file mode 100644
index 0000000000..f3742ef0d2
--- /dev/null
+++ b/engines/gnap/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine gnap "UFOs" no "" "" "highres"
diff --git a/engines/gnap/datarchive.cpp b/engines/gnap/datarchive.cpp
new file mode 100644
index 0000000000..3a586c58ba
--- /dev/null
+++ b/engines/gnap/datarchive.cpp
@@ -0,0 +1,123 @@
+/* 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.
+ *
+ */
+
+#include "common/dcl.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/substream.h"
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+
+#include "engines/util.h"
+
+namespace Gnap {
+
+// DatArchive
+
+DatArchive::DatArchive(const char *filename) {
+ _fd = new Common::File();
+ if (!_fd->open(filename))
+ error("DatArchive::DatArchive() Could not open %s", filename);
+ _fd->skip(8); // Skip signature
+ _fd->skip(2); // Skip unknown
+ _fd->skip(2); // Skip unknown
+ _entriesCount = _fd->readUint32LE();
+ debugC(kDebugBasic, "_entriesCount: %d", _entriesCount);
+ _fd->skip(4); // Skip unknown
+ _entries = new DatEntry[_entriesCount];
+ for (int i = 0; i < _entriesCount; ++i) {
+ _entries[i]._ofs = _fd->readUint32LE();
+ _entries[i]._outSize1 = _fd->readUint32LE();
+ _entries[i]._type = _fd->readUint32LE();
+ _entries[i]._outSize2 = _fd->readUint32LE();
+ }
+}
+
+DatArchive::~DatArchive() {
+ _fd->close();
+ delete _fd;
+ delete[] _entries;
+}
+
+byte *DatArchive::load(int index) {
+ _fd->seek(_entries[index]._ofs);
+ debugC(kDebugBasic, "_entries[index].outSize2: %d; _entries[index].outSize1: %d", _entries[index]._outSize2, _entries[index]._outSize1);
+ byte *buffer = new byte[_entries[index]._outSize1];
+ if (!Common::decompressDCL(_fd, buffer, _entries[index]._outSize2, _entries[index]._outSize1))
+ error("DatArchive::load() Error during decompression of entry %d", index);
+ return buffer;
+}
+
+// DatManager
+
+DatManager::DatManager() {
+ for (int i = 0; i < kMaxDatArchives; ++i)
+ _datArchives[i] = nullptr;
+}
+
+DatManager::~DatManager() {
+ for (int i = 0; i < kMaxDatArchives; ++i)
+ delete _datArchives[i];
+}
+
+void DatManager::open(int index, const char *filename) {
+ close(index);
+ _datArchives[index] = new DatArchive(filename);
+}
+
+void DatManager::close(int index) {
+ delete _datArchives[index];
+ _datArchives[index] = nullptr;
+}
+
+byte *DatManager::loadResource(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->load(entryIndex) : 0;
+}
+
+uint32 DatManager::getResourceType(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->getEntryType(entryIndex) : 0;
+}
+
+uint32 DatManager::getResourceSize(int resourceId) {
+ const int datIndex = ridToDatIndex(resourceId);
+ const int entryIndex = ridToEntryIndex(resourceId);
+ return _datArchives[datIndex] ? _datArchives[datIndex]->getEntrySize(entryIndex) : 0;
+}
+
+int ridToDatIndex(int resourceId) {
+ return (resourceId & 0xFFFF0000) >> 16;
+}
+
+int ridToEntryIndex(int resourceId) {
+ return resourceId & 0xFFFF;
+}
+
+int makeRid(int datIndex, int entryIndex) {
+ return (datIndex << 16) | entryIndex;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/datarchive.h b/engines/gnap/datarchive.h
new file mode 100644
index 0000000000..e9220f8e6f
--- /dev/null
+++ b/engines/gnap/datarchive.h
@@ -0,0 +1,80 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_DATARCHIVE_H
+#define GNAP_DATARCHIVE_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/random.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/system.h"
+#include "engines/engine.h"
+
+namespace Gnap {
+
+struct DatEntry {
+ uint32 _ofs;
+ uint32 _outSize1;
+ uint32 _type;
+ uint32 _outSize2;
+};
+
+class DatArchive {
+public:
+ DatArchive(const char *filename);
+ ~DatArchive();
+ byte *load(int index);
+ int getCount() const { return _entriesCount; }
+ uint32 getEntryType(int index) { return _entries[index]._type; }
+ uint32 getEntrySize(int index) { return _entries[index]._outSize1; }
+protected:
+ Common::File *_fd;
+ int _entriesCount;
+ DatEntry *_entries;
+};
+
+const int kMaxDatArchives = 2;
+
+class DatManager {
+public:
+ DatManager();
+ ~DatManager();
+ void open(int index, const char *filename);
+ void close(int index);
+ byte *loadResource(int resourceId);
+ uint32 getResourceType(int resourceId);
+ uint32 getResourceSize(int resourceId);
+protected:
+ DatArchive *_datArchives[kMaxDatArchives];
+};
+
+int ridToDatIndex(int resourceId);
+int ridToEntryIndex(int resourceId);
+int makeRid(int datIndex, int entryIndex);
+
+} // End of namespace Gnap
+
+#endif // GNAP_DATARCHIVE_H
diff --git a/engines/sci/graphics/paint.cpp b/engines/gnap/debugger.cpp
index 482b81aff1..07f3f6714c 100644
--- a/engines/sci/graphics/paint.cpp
+++ b/engines/gnap/debugger.cpp
@@ -20,25 +20,23 @@
*
*/
-#include "graphics/primitives.h"
+#include "gnap/debugger.h"
+#include "gnap/gnap.h"
-#include "sci/sci.h"
-#include "sci/engine/state.h"
-#include "sci/engine/selector.h"
-#include "sci/graphics/paint.h"
+namespace Gnap {
-namespace Sci {
+Debugger::Debugger(GnapEngine *vm) : GUI::Debugger(), _vm(vm) {
+ // Register methods
+ registerCmd("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots));
-GfxPaint::GfxPaint() {
+ // Set fields
+ _showHotspotNumber = false;
}
-GfxPaint::~GfxPaint() {
-}
-
-void GfxPaint::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
-}
+bool Debugger::Cmd_Hotspots(int argc, const char **argv) {
+ _showHotspotNumber ^= 1;
-void GfxPaint::kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) {
+ return true;
}
-} // End of namespace Sci
+} // End of namespace Gnap
diff --git a/engines/gnap/debugger.h b/engines/gnap/debugger.h
new file mode 100644
index 0000000000..ac83cc5504
--- /dev/null
+++ b/engines/gnap/debugger.h
@@ -0,0 +1,54 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_DEBUGGER_H
+#define GNAP_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class Debugger : public GUI::Debugger {
+private:
+ GnapEngine *_vm;
+public:
+ /*
+ * Specifies whether to show the hotspot IDs
+ */
+ bool _showHotspotNumber;
+protected:
+ /**
+ * List the active hotspots during the current time period
+ */
+ bool Cmd_Hotspots(int argc, const char **argv);
+
+public:
+ Debugger(GnapEngine *vm);
+ virtual ~Debugger() {}
+};
+
+} // End of namespace Gnap
+
+#endif
diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp
new file mode 100644
index 0000000000..7e4ab56d1f
--- /dev/null
+++ b/engines/gnap/detection.cpp
@@ -0,0 +1,196 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "base/plugins.h"
+#include "graphics/thumbnail.h"
+
+static const PlainGameDescriptor gnapGames[] = {
+ { "gnap", "Gnap" },
+ { 0, 0 }
+};
+
+namespace Gnap {
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "gnap", "",
+ {
+ {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12515823},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_TESTING, GUIO0()
+ },
+ {
+ "gnap", "",
+ {
+ {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12995485},
+ AD_LISTEND
+ },
+ Common::RU_RUS, Common::kPlatformWindows, ADGF_TESTING, GUIO0()
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Gnap
+
+class GnapMetaEngine : public AdvancedMetaEngine {
+public:
+ GnapMetaEngine() : AdvancedMetaEngine(Gnap::gameDescriptions, sizeof(ADGameDescription), gnapGames) {
+ _singleId = "gnap";
+ _maxScanDepth = 3;
+ }
+
+ virtual const char *getName() const {
+ return "Gnap";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Gnap (C) Artech Digital Entertainment 1997";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool GnapMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+bool Gnap::GnapEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+void GnapMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+int GnapMetaEngine::getMaximumSaveSlot() const { return 99; }
+
+SaveStateList GnapMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String saveDesc;
+ Common::String pattern = Common::String::format("%s.0##", target);
+ Gnap::GnapSavegameHeader header;
+
+ filenames = saveFileMan->listSavefiles(pattern);
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ const char *ext = strrchr(file->c_str(), '.');
+ int slot = ext ? atoi(ext + 1) : -1;
+
+ if (slot >= 0 && slot < getMaximumSaveSlot()) {
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file);
+
+ if (in) {
+ Gnap::GnapEngine::readSavegameHeader(in, header);
+ saveList.push_back(SaveStateDescriptor(slot, header._saveName));
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+ delete in;
+ }
+ }
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
+ if (file) {
+ char saveIdentBuffer[5];
+ file->read(saveIdentBuffer, 5);
+
+ int32 version = file->readByte();
+ if (version > GNAP_SAVEGAME_VERSION) {
+ delete file;
+ return SaveStateDescriptor();
+ }
+
+ Common::String saveName;
+ char ch;
+ while ((ch = (char)file->readByte()) != '\0')
+ saveName += ch;
+
+ SaveStateDescriptor desc(slot, saveName);
+
+ if (version != 1) {
+ Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file);
+ desc.setThumbnail(thumbnail);
+ }
+
+ int year = file->readSint16LE();
+ int month = file->readSint16LE();
+ int day = file->readSint16LE();
+ int hour = file->readSint16LE();
+ int minutes = file->readSint16LE();
+
+ desc.setSaveDate(year, month, day);
+ desc.setSaveTime(hour, minutes);
+
+ delete file;
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool GnapMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Gnap::GnapEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(GNAP)
+ REGISTER_PLUGIN_DYNAMIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine);
+#endif
diff --git a/engines/gnap/fontdata.h b/engines/gnap/fontdata.h
new file mode 100644
index 0000000000..61128211fc
--- /dev/null
+++ b/engines/gnap/fontdata.h
@@ -0,0 +1,851 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_FONTDATA_H
+#define GNAP_FONTDATA_H
+
+namespace Gnap {
+
+struct FONT_CHAR_INFO {
+ const byte _width; // width, in bits (or pixels), of the character
+ const uint16 _offset; // offset of the character's bitmap, in bytes, into the the FONT_INFO's data array
+
+ FONT_CHAR_INFO(byte width, uint16 offset) : _width(width), _offset(offset) {}
+};
+
+/*
+** Font data for DejaVu Sans 9pt
+*/
+
+/* Character bitmaps for DejaVu Sans 9pt */
+const byte _dejaVuSans9ptCharBitmaps[] = {
+ /* @0 ' ' (5 pixels wide) */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+ 0x00, 0x00, /* */
+
+ /* @10 '!' (1 pixels wide) */
+ 0x1B, 0xF0, /* ## ###### */
+
+ /* @12 '"' (3 pixels wide) */
+ 0x00, 0x70, /* ### */
+ 0x00, 0x00, /* */
+ 0x00, 0x70, /* ### */
+
+ /* @18 '#' (8 pixels wide) */
+ 0x04, 0x00, /* # */
+ 0x14, 0x80, /* # # # */
+ 0x0F, 0x80, /* ##### */
+ 0x04, 0xE0, /* # ### */
+ 0x1C, 0x80, /* ### # */
+ 0x07, 0xC0, /* ##### */
+ 0x04, 0xA0, /* # # # */
+ 0x00, 0x80, /* # */
+
+ /* @34 '$' (5 pixels wide) */
+ 0x09, 0xC0, /* # ### */
+ 0x11, 0x20, /* # # # */
+ 0x7F, 0xF0, /* ########### */
+ 0x12, 0x20, /* # # # */
+ 0x0E, 0x40, /* ### # */
+
+ /* @44 '%' (10 pixels wide) */
+ 0x00, 0xE0, /* ### */
+ 0x01, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x0C, 0xE0, /* ## ### */
+ 0x03, 0x00, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x0E, 0x60, /* ### ## */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x00, /* # # */
+ 0x0E, 0x00, /* ### */
+
+ /* @64 '&' (8 pixels wide) */
+ 0x0E, 0x00, /* ### */
+ 0x19, 0xE0, /* ## #### */
+ 0x10, 0x90, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x12, 0x20, /* # # # */
+ 0x0C, 0x00, /* ## */
+ 0x14, 0x00, /* # # */
+ 0x13, 0x00, /* # ## */
+
+ /* @80 ''' (1 pixels wide) */
+ 0x00, 0x70, /* ### */
+
+ /* @82 '(' (3 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x38, 0x38, /* ### ### */
+ 0x20, 0x08, /* # # */
+
+ /* @88 ')' (3 pixels wide) */
+ 0x20, 0x08, /* # # */
+ 0x38, 0x38, /* ### ### */
+ 0x07, 0xC0, /* ##### */
+
+ /* @94 '*' (5 pixels wide) */
+ 0x01, 0x20, /* # # */
+ 0x00, 0xC0, /* ## */
+ 0x03, 0xF0, /* ###### */
+ 0x00, 0xC0, /* ## */
+ 0x01, 0x20, /* # # */
+
+ /* @104 '+' (7 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x1F, 0xC0, /* ####### */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @118 ',' (1 pixels wide) */
+ 0x38, 0x00, /* ### */
+
+ /* @120 '-' (3 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @126 '.' (1 pixels wide) */
+ 0x18, 0x00, /* ## */
+
+ /* @128 '/' (4 pixels wide) */
+ 0x30, 0x00, /* ## */
+ 0x0E, 0x00, /* ### */
+ 0x01, 0xC0, /* ### */
+ 0x00, 0x30, /* ## */
+
+ /* @136 '0' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x18, 0x30, /* ## ## */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x18, 0x30, /* ## ## */
+ 0x07, 0xC0, /* ##### */
+
+ /* @148 '1' (5 pixels wide) */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+
+ /* @158 '2' (6 pixels wide) */
+ 0x10, 0x20, /* # # */
+ 0x18, 0x10, /* ## # */
+ 0x14, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x11, 0x30, /* # # ## */
+ 0x10, 0xE0, /* # ### */
+
+ /* @170 '3' (6 pixels wide) */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @182 '4' (6 pixels wide) */
+ 0x06, 0x00, /* ## */
+ 0x05, 0x80, /* # ## */
+ 0x04, 0x40, /* # # */
+ 0x04, 0x30, /* # ## */
+ 0x1F, 0xF0, /* ######### */
+ 0x04, 0x00, /* # */
+
+ /* @194 '5' (6 pixels wide) */
+ 0x08, 0xF0, /* # #### */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x19, 0x90, /* ## ## # */
+ 0x0F, 0x00, /* #### */
+
+ /* @206 '6' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x19, 0x20, /* ## # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x19, 0x90, /* ## ## # */
+ 0x0F, 0x20, /* #### # */
+
+ /* @218 '7' (6 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x10, 0x10, /* # # */
+ 0x0C, 0x10, /* ## # */
+ 0x03, 0x10, /* ## # */
+ 0x00, 0xD0, /* ## # */
+ 0x00, 0x30, /* ## */
+
+ /* @230 '8' (6 pixels wide) */
+ 0x0E, 0xE0, /* ### ### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @242 '9' (6 pixels wide) */
+ 0x09, 0xE0, /* # #### */
+ 0x13, 0x30, /* # ## ## */
+ 0x12, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x09, 0x30, /* # # ## */
+ 0x07, 0xC0, /* ##### */
+
+ /* @254 ':' (1 pixels wide) */
+ 0x19, 0x80, /* ## ## */
+
+ /* @256 ';' (1 pixels wide) */
+ 0x39, 0x80, /* ### ## */
+
+ /* @258 '<' (8 pixels wide) */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x0C, 0xC0, /* ## ## */
+ 0x08, 0x40, /* # # */
+
+ /* @274 '=' (8 pixels wide) */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+ 0x05, 0x00, /* # # */
+
+ /* @290 '>' (8 pixels wide) */
+ 0x08, 0x40, /* # # */
+ 0x0C, 0xC0, /* ## ## */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x04, 0x80, /* # # */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+ 0x03, 0x00, /* ## */
+
+ /* @306 '?' (5 pixels wide) */
+ 0x00, 0x20, /* # */
+ 0x00, 0x10, /* # */
+ 0x1B, 0x10, /* ## ## # */
+ 0x00, 0x90, /* # # */
+ 0x00, 0x60, /* ## */
+
+ /* @316 '@' (11 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x10, 0x40, /* # # */
+ 0x20, 0x20, /* # # */
+ 0x47, 0x10, /* # ### # */
+ 0x48, 0x90, /* # # # # */
+ 0x48, 0x90, /* # # # # */
+ 0x48, 0x90, /* # # # # */
+ 0x4F, 0x90, /* # ##### # */
+ 0x28, 0x20, /* # # # */
+ 0x04, 0x60, /* # ## */
+ 0x03, 0x80, /* ### */
+
+ /* @338 'A' (8 pixels wide) */
+ 0x10, 0x00, /* # */
+ 0x0E, 0x00, /* ### */
+ 0x05, 0xC0, /* # ### */
+ 0x04, 0x30, /* # ## */
+ 0x04, 0x30, /* # ## */
+ 0x05, 0xC0, /* # ### */
+ 0x0E, 0x00, /* ### */
+ 0x10, 0x00, /* # */
+
+ /* @354 'B' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0xE0, /* ### ### */
+
+ /* @366 'C' (6 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+
+ /* @378 'D' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @392 'E' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+
+ /* @404 'F' (5 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+
+ /* @414 'G' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0F, 0x20, /* #### # */
+
+ /* @428 'H' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @442 'I' (1 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @444 'J' (3 pixels wide) */
+ 0x40, 0x00, /* # */
+ 0x40, 0x00, /* # */
+ 0x3F, 0xF0, /* ########## */
+
+ /* @450 'K' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x00, /* # */
+ 0x02, 0x80, /* # # */
+ 0x04, 0x40, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+
+ /* @462 'L' (5 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+
+ /* @472 'M' (8 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x60, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x00, 0x60, /* ## */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @488 'N' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x30, /* ## */
+ 0x00, 0xC0, /* ## */
+ 0x01, 0x00, /* # */
+ 0x06, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x1F, 0xF0, /* ######### */
+
+ /* @502 'O' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x20, /* # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @516 'P' (6 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x00, 0xE0, /* ### */
+
+ /* @528 'Q' (7 pixels wide) */
+ 0x07, 0xC0, /* ##### */
+ 0x08, 0x20, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x10, 0x10, /* # # */
+ 0x30, 0x10, /* ## # */
+ 0x48, 0x20, /* # # # */
+ 0x07, 0xC0, /* ##### */
+
+ /* @542 'R' (7 pixels wide) */
+ 0x1F, 0xF0, /* ######### */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x01, 0x10, /* # # */
+ 0x03, 0x10, /* ## # */
+ 0x0C, 0xE0, /* ## ### */
+ 0x10, 0x00, /* # */
+
+ /* @556 'S' (6 pixels wide) */
+ 0x08, 0xE0, /* # ### */
+ 0x11, 0x90, /* # ## # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x0E, 0x20, /* ### # */
+
+ /* @568 'T' (7 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+
+ /* @582 'U' (7 pixels wide) */
+ 0x0F, 0xF0, /* ######## */
+ 0x18, 0x00, /* ## */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x18, 0x00, /* ## */
+ 0x0F, 0xF0, /* ######## */
+
+ /* @596 'V' (8 pixels wide) */
+ 0x00, 0x30, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x06, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x06, 0x00, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x00, 0x30, /* ## */
+
+ /* @612 'W' (11 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0xE0, /* ### */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x80, /* #### */
+ 0x00, 0x70, /* ### */
+ 0x07, 0x80, /* #### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xE0, /* ### */
+ 0x00, 0x10, /* # */
+
+ /* @634 'X' (7 pixels wide) */
+ 0x10, 0x10, /* # # */
+ 0x08, 0x30, /* # ## */
+ 0x06, 0xC0, /* ## ## */
+ 0x01, 0x00, /* # */
+ 0x06, 0xC0, /* ## ## */
+ 0x08, 0x30, /* # ## */
+ 0x10, 0x10, /* # # */
+
+ /* @648 'Y' (7 pixels wide) */
+ 0x00, 0x10, /* # */
+ 0x00, 0x60, /* ## */
+ 0x01, 0x80, /* ## */
+ 0x1E, 0x00, /* #### */
+ 0x01, 0x80, /* ## */
+ 0x00, 0x60, /* ## */
+ 0x00, 0x10, /* # */
+
+ /* @662 'Z' (7 pixels wide) */
+ 0x18, 0x10, /* ## # */
+ 0x14, 0x10, /* # # # */
+ 0x12, 0x10, /* # # # */
+ 0x11, 0x10, /* # # # */
+ 0x10, 0x90, /* # # # */
+ 0x10, 0x50, /* # # # */
+ 0x10, 0x30, /* # ## */
+
+ /* @676 '[' (2 pixels wide) */
+ 0x7F, 0xF0, /* ########### */
+ 0x40, 0x10, /* # # */
+
+ /* @680 '\' (4 pixels wide) */
+ 0x00, 0x30, /* ## */
+ 0x01, 0xC0, /* ### */
+ 0x0E, 0x00, /* ### */
+ 0x30, 0x00, /* ## */
+
+ /* @688 ']' (2 pixels wide) */
+ 0x40, 0x10, /* # # */
+ 0x7F, 0xF0, /* ########### */
+
+ /* @692 '^' (6 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x00, 0x20, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x10, /* # */
+ 0x00, 0x20, /* # */
+ 0x00, 0x40, /* # */
+
+ /* @704 '_' (6 pixels wide) */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+ 0x80, 0x00, /* # */
+
+ /* @716 '`' (2 pixels wide) */
+ 0x00, 0x08, /* # */
+ 0x00, 0x10, /* # */
+
+ /* @720 'a' (6 pixels wide) */
+ 0x0C, 0x80, /* ## # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x0A, 0x40, /* # # # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @732 'b' (6 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @744 'c' (5 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x08, 0x80, /* # # */
+
+ /* @754 'd' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x1F, 0xF8, /* ########## */
+
+ /* @766 'e' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x0A, 0xC0, /* # # ## */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0xC0, /* # # ## */
+ 0x0B, 0x80, /* # ### */
+
+ /* @778 'f' (4 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x00, 0x48, /* # # */
+ 0x00, 0x48, /* # # */
+
+ /* @786 'g' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x58, 0xC0, /* # ## ## */
+ 0x90, 0x40, /* # # # */
+ 0x90, 0x40, /* # # # */
+ 0xD8, 0xC0, /* ## ## ## */
+ 0x7F, 0xC0, /* ######### */
+
+ /* @798 'h' (6 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @810 'i' (1 pixels wide) */
+ 0x1F, 0xD0, /* ####### # */
+
+ /* @812 'j' (2 pixels wide) */
+ 0x80, 0x00, /* # */
+ 0xFF, 0xD0, /* ########## # */
+
+ /* @816 'k' (5 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+ 0x02, 0x00, /* # */
+ 0x05, 0x00, /* # # */
+ 0x08, 0x80, /* # # */
+ 0x10, 0x40, /* # # */
+
+ /* @826 'l' (1 pixels wide) */
+ 0x1F, 0xF8, /* ########## */
+
+ /* @828 'm' (9 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @846 'n' (6 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+ 0x1F, 0x80, /* ###### */
+
+ /* @858 'o' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @870 'p' (6 pixels wide) */
+ 0xFF, 0xC0, /* ########## */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0x0F, 0x80, /* ##### */
+
+ /* @882 'q' (6 pixels wide) */
+ 0x0F, 0x80, /* ##### */
+ 0x18, 0xC0, /* ## ## */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+ 0x18, 0xC0, /* ## ## */
+ 0xFF, 0xC0, /* ########## */
+
+ /* @894 'r' (4 pixels wide) */
+ 0x1F, 0xC0, /* ####### */
+ 0x00, 0x80, /* # */
+ 0x00, 0x40, /* # */
+ 0x00, 0x40, /* # */
+
+ /* @902 's' (5 pixels wide) */
+ 0x09, 0x80, /* # ## */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x0C, 0x80, /* ## # */
+
+ /* @912 't' (4 pixels wide) */
+ 0x00, 0x40, /* # */
+ 0x1F, 0xF0, /* ######### */
+ 0x10, 0x40, /* # # */
+ 0x10, 0x40, /* # # */
+
+ /* @920 'u' (6 pixels wide) */
+ 0x0F, 0xC0, /* ###### */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x10, 0x00, /* # */
+ 0x08, 0x00, /* # */
+ 0x1F, 0xC0, /* ####### */
+
+ /* @932 'v' (6 pixels wide) */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @944 'w' (9 pixels wide) */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x18, 0x00, /* ## */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @962 'x' (6 pixels wide) */
+ 0x10, 0x40, /* # # */
+ 0x0D, 0x80, /* ## ## */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x0D, 0x80, /* ## ## */
+ 0x10, 0x40, /* # # */
+
+ /* @974 'y' (6 pixels wide) */
+ 0x80, 0xC0, /* # ## */
+ 0x83, 0x00, /* # ## */
+ 0x4C, 0x00, /* # ## */
+ 0x38, 0x00, /* ### */
+ 0x07, 0x00, /* ### */
+ 0x00, 0xC0, /* ## */
+
+ /* @986 'z' (5 pixels wide) */
+ 0x18, 0x40, /* ## # */
+ 0x14, 0x40, /* # # # */
+ 0x12, 0x40, /* # # # */
+ 0x11, 0x40, /* # # # */
+ 0x10, 0xC0, /* # ## */
+
+ /* @996 '{' (5 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x7D, 0xF0, /* ##### ##### */
+ 0x40, 0x10, /* # # */
+ 0x40, 0x10, /* # # */
+
+ /* @1006 '|' (1 pixels wide) */
+ 0xFF, 0xF0, /* ############ */
+
+ /* @1008 '}' (5 pixels wide) */
+ 0x40, 0x10, /* # # */
+ 0x40, 0x10, /* # # */
+ 0x7D, 0xF0, /* ##### ##### */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+
+ /* @1018 '~' (8 pixels wide) */
+ 0x02, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x01, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x02, 0x00, /* # */
+ 0x01, 0x00, /* # */
+};
+
+/* Character descriptors for DejaVu Sans 9pt */
+/* { [Char width in bits], [Offset into dejaVuSans9ptCharBitmaps in bytes] } */
+const FONT_CHAR_INFO _dejaVuSans9ptCharDescriptors[] = {
+ FONT_CHAR_INFO(5, 0), /* */
+ FONT_CHAR_INFO(1, 10), /* ! */
+ FONT_CHAR_INFO(3, 12), /* " */
+ FONT_CHAR_INFO(8, 18), /* # */
+ FONT_CHAR_INFO(5, 34), /* $ */
+ FONT_CHAR_INFO(10, 44), /* % */
+ FONT_CHAR_INFO(8, 64), /* & */
+ FONT_CHAR_INFO(1, 80), /* ' */
+ FONT_CHAR_INFO(3, 82), /* ( */
+ FONT_CHAR_INFO(3, 88), /* ) */
+ FONT_CHAR_INFO(5, 94), /* * */
+ FONT_CHAR_INFO(7, 104), /* + */
+ FONT_CHAR_INFO(1, 118), /* , */
+ FONT_CHAR_INFO(3, 120), /* - */
+ FONT_CHAR_INFO(1, 126), /* . */
+ FONT_CHAR_INFO(4, 128), /* / */
+ FONT_CHAR_INFO(6, 136), /* 0 */
+ FONT_CHAR_INFO(5, 148), /* 1 */
+ FONT_CHAR_INFO(6, 158), /* 2 */
+ FONT_CHAR_INFO(6, 170), /* 3 */
+ FONT_CHAR_INFO(6, 182), /* 4 */
+ FONT_CHAR_INFO(6, 194), /* 5 */
+ FONT_CHAR_INFO(6, 206), /* 6 */
+ FONT_CHAR_INFO(6, 218), /* 7 */
+ FONT_CHAR_INFO(6, 230), /* 8 */
+ FONT_CHAR_INFO(6, 242), /* 9 */
+ FONT_CHAR_INFO(1, 254), /* : */
+ FONT_CHAR_INFO(1, 256), /* ; */
+ FONT_CHAR_INFO(8, 258), /* < */
+ FONT_CHAR_INFO(8, 274), /* = */
+ FONT_CHAR_INFO(8, 290), /* > */
+ FONT_CHAR_INFO(5, 306), /* ? */
+ FONT_CHAR_INFO(11, 316), /* @ */
+ FONT_CHAR_INFO(8, 338), /* A */
+ FONT_CHAR_INFO(6, 354), /* B */
+ FONT_CHAR_INFO(6, 366), /* C */
+ FONT_CHAR_INFO(7, 378), /* D */
+ FONT_CHAR_INFO(6, 392), /* E */
+ FONT_CHAR_INFO(5, 404), /* F */
+ FONT_CHAR_INFO(7, 414), /* G */
+ FONT_CHAR_INFO(7, 428), /* H */
+ FONT_CHAR_INFO(1, 442), /* I */
+ FONT_CHAR_INFO(3, 444), /* J */
+ FONT_CHAR_INFO(6, 450), /* K */
+ FONT_CHAR_INFO(5, 462), /* L */
+ FONT_CHAR_INFO(8, 472), /* M */
+ FONT_CHAR_INFO(7, 488), /* N */
+ FONT_CHAR_INFO(7, 502), /* O */
+ FONT_CHAR_INFO(6, 516), /* P */
+ FONT_CHAR_INFO(7, 528), /* Q */
+ FONT_CHAR_INFO(7, 542), /* R */
+ FONT_CHAR_INFO(6, 556), /* S */
+ FONT_CHAR_INFO(7, 568), /* T */
+ FONT_CHAR_INFO(7, 582), /* U */
+ FONT_CHAR_INFO(8, 596), /* V */
+ FONT_CHAR_INFO(11, 612), /* W */
+ FONT_CHAR_INFO(7, 634), /* X */
+ FONT_CHAR_INFO(7, 648), /* Y */
+ FONT_CHAR_INFO(7, 662), /* Z */
+ FONT_CHAR_INFO(2, 676), /* [ */
+ FONT_CHAR_INFO(4, 680), /* \ */
+ FONT_CHAR_INFO(2, 688), /* ] */
+ FONT_CHAR_INFO(6, 692), /* ^ */
+ FONT_CHAR_INFO(6, 704), /* _ */
+ FONT_CHAR_INFO(2, 716), /* ` */
+ FONT_CHAR_INFO(6, 720), /* a */
+ FONT_CHAR_INFO(6, 732), /* b */
+ FONT_CHAR_INFO(5, 744), /* c */
+ FONT_CHAR_INFO(6, 754), /* d */
+ FONT_CHAR_INFO(6, 766), /* e */
+ FONT_CHAR_INFO(4, 778), /* f */
+ FONT_CHAR_INFO(6, 786), /* g */
+ FONT_CHAR_INFO(6, 798), /* h */
+ FONT_CHAR_INFO(1, 810), /* i */
+ FONT_CHAR_INFO(2, 812), /* j */
+ FONT_CHAR_INFO(5, 816), /* k */
+ FONT_CHAR_INFO(1, 826), /* l */
+ FONT_CHAR_INFO(9, 828), /* m */
+ FONT_CHAR_INFO(6, 846), /* n */
+ FONT_CHAR_INFO(6, 858), /* o */
+ FONT_CHAR_INFO(6, 870), /* p */
+ FONT_CHAR_INFO(6, 882), /* q */
+ FONT_CHAR_INFO(4, 894), /* r */
+ FONT_CHAR_INFO(5, 902), /* s */
+ FONT_CHAR_INFO(4, 912), /* t */
+ FONT_CHAR_INFO(6, 920), /* u */
+ FONT_CHAR_INFO(6, 932), /* v */
+ FONT_CHAR_INFO(9, 944), /* w */
+ FONT_CHAR_INFO(6, 962), /* x */
+ FONT_CHAR_INFO(6, 974), /* y */
+ FONT_CHAR_INFO(5, 986), /* z */
+ FONT_CHAR_INFO(5, 996), /* { */
+ FONT_CHAR_INFO(1, 1006), /* | */
+ FONT_CHAR_INFO(5, 1008), /* ) */
+ FONT_CHAR_INFO(8, 1018) /* ~ */
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_RESOURCE_H
diff --git a/engines/gnap/gamesys.cpp b/engines/gnap/gamesys.cpp
new file mode 100644
index 0000000000..08a4af39ee
--- /dev/null
+++ b/engines/gnap/gamesys.cpp
@@ -0,0 +1,1276 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gamesys.h"
+#include "gnap/fontdata.h"
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "image/bmp.h"
+
+namespace Gnap {
+
+void GfxItem::testUpdRect(const Common::Rect &updRect) {
+ Common::Rect intersectingRect;
+ if (!_updFlag && _prevFrame._spriteId != -1 &&
+ _updRectsCount < 20 && intersectRect(intersectingRect, _prevFrame._rect, updRect))
+ _updRects[_updRectsCount++] = intersectingRect;
+}
+
+// GameSys
+
+GameSys::GameSys(GnapEngine *vm) : _vm(vm) {
+ _newSpriteDrawItemsCount = 0;
+ _removeSequenceItemsCount = 0;
+ _removeSpriteDrawItemsCount = 0;
+ _grabSpriteId = -1;
+ _grabSpriteChanged = false;
+ _reqRemoveSequenceItem = false;
+ _removeSequenceItemSequenceId = -1;
+ _removeSequenceItemValue = 0;
+ _gfxItemsCount = 0;
+ _animationsCount = 0;
+ _animationsDone = false;
+ _backgroundImageValue3 = 0;
+ _backgroundImageValue1 = 0;
+ _backgroundImageValue4 = 1000;
+ _backgroundImageValue2 = 1000;
+ _gameSysClock = 0;
+ _lastUpdateClock = 0;
+ _backgroundSurface = nullptr;
+ _frontSurface = nullptr;
+ for (int i = 0; i < kMaxAnimations; ++i) {
+ _animations[i]._sequenceId = -1;
+ _animations[i]._id = -1;
+ _animations[i]._status = 0;
+ }
+ _removeSequenceItems->_sequenceId = -1;
+ _removeSequenceItems->_id = -1;
+ _removeSequenceItems->_forceFrameReset = false;
+ _removeSpriteDrawItems->_id = -1;
+ _removeSpriteDrawItems->_surface = nullptr;
+
+ _grabSpriteSurface1 = _grabSpriteSurface2 = nullptr;
+
+ _screenRect = Common::Rect(0, 0, 800, 600);
+}
+
+GameSys::~GameSys() {
+ if (_frontSurface)
+ _frontSurface->free();
+ delete _frontSurface;
+}
+
+void GameSys::insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y) {
+ debugC(kDebugBasic, "GameSys::insertSequence() [%08X, %d] -> [%08X, %d] (%d, %d)", sequenceId, id, sequenceId2, id2, x, y);
+ Sequence sequence;
+ SequenceResource *sequenceResource = _vm->_sequenceCache->get(sequenceId);
+ sequenceResource->_sequenceId = sequenceId;
+ sequence._sequenceId = sequenceId;
+ sequence._id = id != -1 ? id : sequenceResource->_defaultId;
+ sequence._sequenceId2 = sequenceId2 != (int32)0x80000000 ? sequenceId2 : sequenceResource->_sequenceId2;
+ sequence._id2 = id2 != -1 ? id2 : sequenceResource->_defaultId2;
+ sequence._flags = flags != -1 ? flags : sequenceResource->_flags;
+ sequence._totalDuration = totalDuration != -1 ? totalDuration : sequenceResource->_totalDuration;
+ sequence._x = (x < 10000 && x > -10000) ? x : sequenceResource->_xOffs;
+ sequence._y = (y < 10000 && y > -10000) ? y : sequenceResource->_yOffs;
+ _fatSequenceItems.push_back(sequence);
+}
+
+void GameSys::insertDirtyRect(const Common::Rect &rect) {
+ _dirtyRects.push_back(rect);
+}
+
+void GameSys::removeSequence(int sequenceId, int id, bool resetFl) {
+ //WaitForSingleObject(removeSequence2Mutex, INFINITE);
+ if (_removeSequenceItemsCount < kMaxSequenceItems) {
+ _removeSequenceItems[_removeSequenceItemsCount]._sequenceId = sequenceId;
+ _removeSequenceItems[_removeSequenceItemsCount]._id = id;
+ _removeSequenceItems[_removeSequenceItemsCount]._forceFrameReset = resetFl;
+ ++_removeSequenceItemsCount;
+ //ResetEvent(removeSequenceItemsEvent);
+ //ReleaseMutex(removeSequence2Mutex);
+ //WaitForSingleObject(removeSequenceItemsEvent, INFINITE);
+ }
+}
+
+void GameSys::invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2) {
+ //WaitForSingleObject(grabSpriteMutex, INFINITE);
+ _grabSpriteId = id;
+ _grabSpriteRect = rect;
+ _grabSpriteSurface2 = surface2;
+ _grabSpriteSurface1 = surface1;
+ //ResetEvent(grabSpriteEvent);
+ _grabSpriteChanged = true;
+ //ReleaseMutex(grabSpriteMutex);
+ //WaitForSingleObject(grabSpriteEvent, INFINITE);
+}
+
+void GameSys::requestClear2(bool resetFl) {
+ _fatSequenceItems.clear();
+ _seqItems.clear();
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ if (resetFl) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ }
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::requestClear1() {
+ _gfxItemsCount = 0;
+ _fatSequenceItems.clear();
+ _seqItems.clear();
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::requestRemoveSequence(int sequenceId, int id) {
+ //WaitForSingleObject(removeSequence2Mutex, INFINITE);
+ _reqRemoveSequenceItem = true;
+ _removeSequenceItemSequenceId = sequenceId;
+ _removeSequenceItemValue = id;
+
+ handleReqRemoveSequenceItem(); //CHECKME?
+
+ //ResetEvent(reqClearEvent);
+ //ReleaseMutex(removeSequence2Mutex);
+ //WaitForSingleObject(reqClearEvent, INFINITE);
+}
+
+void GameSys::waitForUpdate() {
+ //ResetEvent(updateEvent);
+ //WaitForSingleObject(updateEvent, INFINITE);
+ while ( !_animationsDone) {
+ _vm->gameUpdateTick();
+ }
+}
+
+int GameSys::isSequenceActive(int sequenceId, int id) {
+ for (uint i = 0; i < _seqItems.size(); ++i)
+ if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id)
+ return true;
+ return false;
+}
+
+void GameSys::setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7) {
+ debugC(kDebugBasic, "GameSys::setBackgroundSurface() Setting background image");
+
+ _backgroundSurface = surface;
+ if (!_backgroundSurface) {
+ return;
+ }
+
+ if (!_frontSurface || _frontSurface->w != surface->w || _frontSurface->h != surface->h) {
+ debugC(kDebugBasic, "GameSys::setBackgroundSurface() Creating background working surface");
+ if (_frontSurface)
+ _frontSurface->free();
+ delete _frontSurface;
+ _frontSurface = new Graphics::Surface();
+ _frontSurface->create(surface->w, surface->h, surface->format);
+ }
+
+ memcpy(_frontSurface->getPixels(), surface->getPixels(), surface->pitch * surface->h);
+ _vm->_system->copyRectToScreen(_frontSurface->getPixels(), _frontSurface->pitch, 0, 0, _frontSurface->w, _frontSurface->h);
+
+ _backgroundImageValue1 = a4;
+ _backgroundImageValue3 = a6;
+ _backgroundImageValue2 = a5;
+ _backgroundImageValue4 = a7;
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+}
+
+void GameSys::setScaleValues(int a1, int a2, int a3, int a4) {
+ _backgroundImageValue1 = a1;
+ _backgroundImageValue3 = a3;
+ _backgroundImageValue2 = a2;
+ _backgroundImageValue4 = a4;
+}
+
+void GameSys::insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id) {
+ if (surface && _newSpriteDrawItemsCount < kMaxSpriteDrawItems) {
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._id = id;
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._rect = Common::Rect(x, y, x + surface->w, y + surface->h);
+ _newSpriteDrawItems[_newSpriteDrawItemsCount]._surface = surface;
+ ++_newSpriteDrawItemsCount;
+ }
+}
+
+void GameSys::removeSpriteDrawItem(Graphics::Surface *surface, int id) {
+ if (surface && _removeSpriteDrawItemsCount < kMaxSpriteDrawItems) {
+ _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._id = id;
+ _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._surface = surface;
+ ++_removeSpriteDrawItemsCount;
+ }
+}
+
+void GameSys::drawSpriteToBackground(int x, int y, int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+ int spriteWidth = spriteResource->_width;
+ int spriteHeight = spriteResource->_height;
+ Common::Rect dstRect(0, 0, spriteWidth, spriteHeight);
+ blitSprite32(_backgroundSurface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, spriteResource->_transparent);
+ _vm->_spriteCache->release(resourceId);
+
+ // Add dirty rect so the modified background is redrawn
+ insertDirtyRect(Common::Rect(x, y, x + spriteWidth, y + spriteHeight));
+}
+
+Graphics::Surface *GameSys::allocSurface(int width, int height) {
+ Graphics::Surface *surface = new Graphics::Surface();
+ surface->create(width, height, _backgroundSurface->format);
+ surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0xFFFFFF00);
+ return surface;
+}
+
+Graphics::Surface *GameSys::createSurface(int resourceId) {
+ debugC(kDebugBasic, "GameSys::createSurface() resourceId: %08X", resourceId);
+
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ Graphics::Surface *surface = allocSurface(spriteResource->_width, spriteResource->_height);
+ _vm->_spriteCache->release(resourceId);
+
+ drawSpriteToSurface(surface, 0, 0, resourceId);
+
+ return surface;
+}
+
+void GameSys::drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+ Common::Rect dstRect(0, 0, spriteResource->_width, spriteResource->_height);
+ blitSprite32(surface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, true);
+ _vm->_spriteCache->release(resourceId);
+}
+
+void GameSys::drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text) {
+ bool doDirty = false;
+
+ if (!surface) {
+ surface = _backgroundSurface;
+ doDirty = true;
+ }
+
+ uint32 color = surface->format.RGBToColor(r, g, b);
+ if (_vm->_font) {
+ _vm->_font->drawString(surface, text, x, y, _vm->_font->getStringWidth(text), color);
+
+ if (doDirty)
+ insertDirtyRect(Common::Rect(x, y, x + _vm->_font->getStringWidth(text), y + _vm->_font->getFontHeight()));
+ } else {
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ int w = _dejaVuSans9ptCharDescriptors[c]._width;
+ const byte *data = _dejaVuSans9ptCharBitmaps + _dejaVuSans9ptCharDescriptors[c]._offset;
+ for (int xc = 0; xc < w; ++xc) {
+ for (int yc = 15; yc >= 0; --yc) {
+ byte *dst = (byte *)surface->getBasePtr(x + xc, y + yc);
+ if (data[1 - (yc >> 3)] & (1 << (yc & 7)))
+ WRITE_LE_UINT32(dst, color);
+ }
+ data += 2;
+ }
+ x += w + 1;
+ }
+
+ if (doDirty)
+ insertDirtyRect(Common::Rect(x, y, x + getTextWidth(text), y + 16));
+ }
+}
+
+int GameSys::getTextHeight(const char *text) {
+ byte height = 0;
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ height = MAX(height, _dejaVuSans9ptCharDescriptors[c]._width);
+ }
+ return height;
+}
+
+int GameSys::getTextWidth(const char *text) {
+ int width = 0;
+ for (const char *cp = text; *cp != 0; ++cp) {
+ byte c = *cp;
+ if (c < 32 || c >= 127)
+ c = (byte)'_';
+ c -= 32;
+ width += _dejaVuSans9ptCharDescriptors[c]._width + 1;
+ }
+ return width;
+}
+
+void GameSys::fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b) {
+ Common::Rect rect(x, y, x + width, y + height);
+ if (!surface) {
+ _backgroundSurface->fillRect(rect, _backgroundSurface->format.RGBToColor(r, g, b));
+ insertDirtyRect(rect);
+ } else {
+ surface->fillRect(rect, surface->format.RGBToColor(r, g, b));
+ }
+}
+
+void GameSys::setAnimation(int sequenceId, int id, int animationIndex) {
+ if (animationIndex < kMaxAnimations) {
+ _animations[animationIndex]._sequenceId = sequenceId;
+ _animations[animationIndex]._id = id;
+ _animations[animationIndex]._status = 0;
+ }
+}
+
+int GameSys::getAnimationStatus(int animationIndex) {
+ int result = -1;
+ if (animationIndex < kMaxAnimations)
+ result = _animations[animationIndex]._status;
+ return result;
+}
+
+int GameSys::getSpriteWidthById(int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ const int width = spriteResource->_width;
+ _vm->_spriteCache->release(resourceId);
+ return width;
+}
+
+int GameSys::getSpriteHeightById(int resourceId) {
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ const int height = spriteResource->_height;
+ _vm->_spriteCache->release(resourceId);
+ return height;
+}
+
+Graphics::Surface *GameSys::loadBitmap(int resourceId) {
+ debugC(kDebugBasic, "GameSys::loadBitmap() resourceId: %08X", resourceId);
+ if (_vm->_dat->getResourceType(resourceId) != 1)
+ return nullptr;
+ byte *resourceData = _vm->_dat->loadResource(resourceId);
+ uint32 resourceSize = _vm->_dat->getResourceSize(resourceId);
+ Common::MemoryReadStream stream(resourceData, resourceSize, DisposeAfterUse::NO);
+ Graphics::Surface *bmpSurface;
+ Image::BitmapDecoder bmp;
+ if (!bmp.loadStream(stream))
+ error("GameSys::loadBitmap() Could not load bitmap resource %08X", resourceId);
+ bmpSurface = bmp.getSurface()->convertTo(_vm->_system->getScreenFormat());
+ delete[] resourceData;
+ return bmpSurface;
+}
+
+void GameSys::drawBitmap(int resourceId) {
+ assert(_backgroundSurface);
+
+ Graphics::Surface *bmpSurface = loadBitmap(resourceId);
+ if (!bmpSurface)
+ error("GameSys::drawBitmap() Error loading the bitmap");
+
+ if (bmpSurface->format != _backgroundSurface->format
+ || bmpSurface->w != _backgroundSurface->w || bmpSurface->h != _backgroundSurface->h)
+ error("GameSys::drawBitmap() Different bitmap properties than current background");
+
+ byte *src = (byte *)bmpSurface->getPixels();
+ byte *dst = (byte *)_backgroundSurface->getPixels();
+ const int pitch = bmpSurface->pitch;
+ int height = bmpSurface->h;
+ while (height--) {
+ memcpy(dst, src, pitch);
+ src += pitch;
+ dst += pitch;
+ }
+
+ bmpSurface->free();
+ delete bmpSurface;
+
+ insertDirtyRect(Common::Rect(0, 0, 800, 600));
+}
+
+Sequence *GameSys::seqFind(int sequenceId, int id, int *outIndex) {
+ for (uint i = 0; i < _seqItems.size(); ++i)
+ if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id) {
+ if (outIndex)
+ *outIndex = i;
+ return &_seqItems[i];
+ }
+ return nullptr;
+}
+
+int GameSys::seqLocateGfx(int sequenceId, int id, int *outGfxIndex) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ if (outGfxIndex)
+ *outGfxIndex = i;
+ return gfxItem->_sequenceId;
+ }
+ if (gfxItem->_id > id) {
+ if (outGfxIndex)
+ *outGfxIndex = i;
+ return 0;
+ }
+ }
+ if (outGfxIndex)
+ *outGfxIndex = _gfxItemsCount;
+ return 0;
+}
+
+void GameSys::seqInsertGfx(int index, int duration) {
+ Sequence *seqItem = &_seqItems[index];
+ SequenceResource *sequenceResource = _vm->_sequenceCache->get(seqItem->_sequenceId);
+
+ if (sequenceResource->_animationsCount > 50 - _gfxItemsCount)
+ return;
+
+ int gfxIndex;
+ seqLocateGfx(seqItem->_sequenceId, seqItem->_id, &gfxIndex);
+
+ if (gfxIndex != _gfxItemsCount)
+ memmove(&_gfxItems[gfxIndex + sequenceResource->_animationsCount], &_gfxItems[gfxIndex], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
+ _gfxItemsCount += sequenceResource->_animationsCount;
+
+ for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i + gfxIndex];
+ SequenceAnimation *animation = &sequenceResource->_animations[i];
+
+ debugC(kDebugBasic, "GameSys::seqInsertGfx() seqItem->sequenceId: %08X", seqItem->_sequenceId);
+
+ gfxItem->_sequenceId = seqItem->_sequenceId;
+ gfxItem->_id = seqItem->_id;
+ gfxItem->_animation = animation;
+ gfxItem->_currFrameNum = 0;
+ gfxItem->_flags = 0;
+ gfxItem->_delayTicks = seqItem->_totalDuration + animation->_additionalDelay;
+ gfxItem->_updFlag = false;
+ gfxItem->_updRectsCount = 0;
+ gfxItem->_prevFrame._duration = 0;
+ gfxItem->_prevFrame._spriteId = -1;
+ gfxItem->_prevFrame._soundId = -1;
+ int totalDuration = duration;
+ if ((seqItem->_flags & kSeqUnk) && totalDuration > 0) {
+ gfxItem->_prevFrame._duration = 1;
+ if (gfxItem->_delayTicks <= totalDuration)
+ gfxItem->_delayTicks = 0;
+ else
+ gfxItem->_delayTicks -= totalDuration + 1;
+ gfxItem->_updFlag = false;
+ } else if (gfxItem->_delayTicks <= totalDuration) {
+ int j;
+ totalDuration -= gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ for (j = gfxItem->_currFrameNum; j < animation->_framesCount && animation->frames[j]._duration <= totalDuration; ++j) {
+ if (animation->frames[j]._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[j]._soundId);
+ totalDuration -= animation->frames[j]._duration;
+ }
+ if (animation->_framesCount > j)
+ gfxItem->_currFrame = animation->frames[j++];
+ else
+ gfxItem->_currFrame = animation->frames[j - 1];
+ if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
+ gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
+ // Update sprite scaling
+ if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
+ int scaleValue = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
+ (_backgroundImageValue4 - _backgroundImageValue2) /
+ (_backgroundImageValue3 - _backgroundImageValue1);
+ gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - scaleValue * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
+ gfxItem->_currFrame._rect.right = scaleValue * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
+ gfxItem->_currFrame._isScaled = true;
+ }
+ gfxItem->_currFrame._duration -= totalDuration;
+ if (gfxItem->_currFrame._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
+ gfxItem->_currFrameNum = j;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_delayTicks -= totalDuration + 1;
+ gfxItem->_updFlag = false;
+ }
+ }
+
+ for (int k = 0; k < kMaxAnimations; ++k) {
+ if (_animations[k]._sequenceId != -1 && _animations[k]._sequenceId == seqItem->_sequenceId && _animations[k]._id == seqItem->_id) {
+ _animations[k]._status = 1;
+ break;
+ }
+ }
+}
+
+void GameSys::seqRemoveGfx(int sequenceId, int id) {
+ int gfxIndex;
+ if (seqLocateGfx(sequenceId, id, &gfxIndex)) {
+ GfxItem *gfxItem = &_gfxItems[gfxIndex];
+ while (gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ if (gfxItem->_prevFrame._spriteId == -1) {
+ --_gfxItemsCount;
+ if (gfxIndex != _gfxItemsCount)
+ memmove(&_gfxItems[gfxIndex], &_gfxItems[gfxIndex + 1], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex));
+ } else {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ ++gfxIndex;
+ gfxItem = &_gfxItems[gfxIndex];
+ }
+ }
+ }
+}
+
+bool GameSys::updateSequenceDuration(int sequenceId, int id, int *outDuration) {
+ bool found = false;
+ int duration = 0x7FFFFFFF;
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) {
+ found = true;
+ SequenceAnimation *animation = gfxItem->_animation;
+ if (animation) {
+ if (gfxItem->_currFrameNum < animation->_framesCount)
+ return false;
+ if (gfxItem->_updFlag) {
+ if (gfxItem->_currFrame._duration > 0)
+ return false;
+ if (-gfxItem->_currFrame._duration < duration)
+ duration = -gfxItem->_currFrame._duration;
+ } else {
+ if (gfxItem->_prevFrame._duration > 0)
+ return false;
+ if (-gfxItem->_prevFrame._duration < duration)
+ duration = -gfxItem->_prevFrame._duration;
+ }
+ }
+ }
+ }
+ if (found)
+ *outDuration = duration;
+ return found;
+}
+
+void GameSys::updateAnimationsStatus(int sequenceId, int id) {
+ Animation *foundAnimation = nullptr;
+ for (int animationIndex = 0; animationIndex < kMaxAnimations; ++animationIndex) {
+ Animation *animation = &_animations[animationIndex];
+ if (animation->_sequenceId != -1 && animation->_sequenceId == sequenceId && animation->_id == id) {
+ foundAnimation = animation;
+ break;
+ }
+ }
+
+ if (!foundAnimation)
+ return;
+
+ bool foundSequence = false;
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ SequenceAnimation *animation = gfxItem->_animation;
+ if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id && animation) {
+ foundSequence = true;
+ if (animation->_framesCount > gfxItem->_currFrameNum ||
+ (gfxItem->_updFlag && gfxItem->_currFrame._duration > 1) ||
+ gfxItem->_prevFrame._duration > 1)
+ foundSequence = false;
+ break;
+ }
+ }
+
+ if (foundSequence) {
+ foundAnimation->_sequenceId = -1;
+ foundAnimation->_status = 2;
+ }
+}
+
+void GameSys::restoreBackgroundRect(const Common::Rect &rect) {
+ Common::Rect clipRect;
+ if (!intersectRect(clipRect, rect, _screenRect))
+ return;
+ byte *src = (byte *)_backgroundSurface->getBasePtr(clipRect.left, clipRect.top);
+ byte *dst = (byte *)_frontSurface->getBasePtr(clipRect.left, clipRect.top);
+ const int bytes = _backgroundSurface->format.bytesPerPixel * clipRect.width();
+ int height = clipRect.height();
+ while (height--) {
+ memcpy(dst, src, bytes);
+ src += _backgroundSurface->pitch;
+ dst += _frontSurface->pitch;
+ }
+}
+
+void GameSys::blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
+ Common::Rect &sourceRect, bool transparent) {
+
+ const int sourcePitch = sourceSurface->pitch;
+ byte *dst = (byte *)destSurface->getBasePtr(x, y);
+ byte *src = (byte *)sourceSurface->getBasePtr(sourceRect.left, sourceRect.top);
+ int width = sourceRect.width();
+ int height = sourceRect.height();
+ while (height--) {
+ byte *rsrc = src;
+ byte *rdst = dst;
+ for (int xc = 0; xc < width; ++xc) {
+ uint32 pixel = READ_UINT32(rsrc);
+ if (!transparent || pixel != 0xFFFFFF00)
+ WRITE_UINT32(rdst, pixel);
+ rsrc += 4;
+ rdst += 4;
+ }
+ dst += destSurface->pitch;
+ src += sourcePitch;
+ }
+}
+
+void GameSys::blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
+ int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent) {
+
+ const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
+ byte *dst = (byte *)destSurface->getBasePtr(x, y);
+ byte *src = sourcePixels + sourceRect.left + sourcePitch * sourceRect.top;
+ int width = sourceRect.width();
+ int height = sourceRect.height();
+ while (height--) {
+ byte *rdst = dst;
+ for (int xc = 0; xc < width; ++xc) {
+ byte srcPixel = src[xc];
+ if (!transparent || srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ rdst[0] = 0xFF;
+ rdst[1] = rgb & 0x000000FF;
+ rdst[2] = (rgb & 0x0000FF00) >> 8;
+ rdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ rdst += 4;
+ }
+ dst += destSurface->pitch;
+ src += sourcePitch;
+ }
+}
+
+void GameSys::blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
+ Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette) {
+
+ if (frameRect.height() <= 0 || frameRect.width() <= 0)
+ return;
+
+ const int ys = ((sourceRect.bottom - sourceRect.top - 1) << 16) / (frameRect.bottom - frameRect.top - 1);
+ const int xs = ((sourceRect.right - sourceRect.left - 1) << 16) / (frameRect.right - frameRect.left - 1);
+ const int destPitch = destSurface->pitch;
+ const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC;
+
+ if (!frameRect.equals(destRect)) {
+ byte *dst = (byte *)destSurface->getBasePtr(destRect.left, destRect.top);
+ byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ const int height = destRect.bottom - destRect.top;
+ const int width = destRect.right - destRect.left;
+ int yi = ys * (destRect.top - frameRect.top);
+ byte *hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ for (int i = 0; i < height; ++i) {
+ byte *wdst = dst;
+ int xi = xs * (destRect.left - frameRect.left);
+ byte *wsrc = hsrc + ((xi + 0x8000) >> 16);
+ for (int j = 0; j < width; ++j) {
+ byte srcPixel = *wsrc;
+ if (srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ wdst[0] = 0xFF;
+ wdst[1] = rgb & 0x000000FF;
+ wdst[2] = (rgb & 0x0000FF00) >> 8;
+ wdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ wdst += 4;
+ xi += xs;
+ wsrc = hsrc + ((xi + 0x8000) >> 16);
+ }
+ dst += destPitch;
+ yi += ys;
+ hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ }
+ } else {
+ byte *dst = (byte *)destSurface->getBasePtr(frameRect.left, frameRect.top);
+ byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ const int height = frameRect.bottom - frameRect.top;
+ const int width = frameRect.right - frameRect.left;
+ byte *hsrc = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left;
+ int yi = 0;
+ for (int i = 0; i < height; ++i) {
+ byte *wdst = dst;
+ byte *wsrc = hsrc;
+ int xi = 0;
+ for (int j = 0; j < width; ++j) {
+ byte srcPixel = *wsrc;
+ if (srcPixel) {
+ uint32 rgb = sourcePalette[srcPixel];
+ wdst[0] = 0xFF;
+ wdst[1] = rgb & 0x000000FF;
+ wdst[2] = (rgb & 0x0000FF00) >> 8;
+ wdst[3] = (rgb & 0x00FF0000) >> 16;
+ }
+ wdst += 4;
+ xi += xs;
+ wsrc = hsrc + ((xi + 0x8000) >> 16);
+ }
+ dst += destPitch;
+ yi += ys;
+ hsrc = src + sourcePitch * ((yi + 0x8000) >> 16);
+ }
+ }
+
+}
+
+void GameSys::seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect) {
+ debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() rect: (%d, %d, %d, %d)",
+ frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
+
+ Common::Rect srcRect = subRect ? *subRect : frame._rect;
+ Common::Rect clipRect;
+
+ if (!intersectRect(clipRect, srcRect, _screenRect)) {
+ debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() Surface not inside screen");
+ return;
+ }
+
+ const int x = clipRect.left, y = clipRect.top;
+
+ clipRect.translate(-frame._rect.left, -frame._rect.top);
+
+ // TODO Save transparent flag somewhere
+ blitSurface32(_frontSurface, x, y, surface, clipRect, true);
+}
+
+void GameSys::seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect) {
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() spriteId: %04X; rect: (%d, %d, %d, %d)",
+ frame._spriteId, frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom);
+
+ Common::Rect srcRect = subRect ? *subRect : frame._rect;
+ Common::Rect clipRect;
+
+ if (!intersectRect(clipRect, srcRect, _screenRect)) {
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() Sprite not inside screen");
+ return;
+ }
+
+ uint32 *sourcePalette = spriteResource->_palette;
+ byte *sourcePixels = spriteResource->_pixels;
+
+ const int x = clipRect.left, y = clipRect.top;
+
+ debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() destX: %d; destY: %d; frame.isScaled: %d", x, y, frame._isScaled ? 1 : 0);
+
+ // 32bit sprite drawing
+ if (frame._isScaled) {
+ Common::Rect sourceRect(0, 0, spriteResource->_width, spriteResource->_height);
+ blitSpriteScaled32(_frontSurface, frame._rect, clipRect, sourcePixels, spriteResource->_width, sourceRect, sourcePalette);
+ } else {
+ clipRect.translate(-frame._rect.left, -frame._rect.top);
+ blitSprite32(_frontSurface, x, y, sourcePixels, spriteResource->_width, clipRect, sourcePalette, true);
+ }
+}
+
+void GameSys::drawSprites() {
+ debugC(kDebugBasic, "GameSys::drawSprites() _gfxItemsCount: %d", _gfxItemsCount);
+
+ // Restore dirty background and collect rects to be redrawn for all sprites
+ // which aren't marked to be redrawn yet
+ Common::Rect intersectingRect;
+ for (uint i = 0; i < _dirtyRects.size(); ++i) {
+ restoreBackgroundRect(_dirtyRects[i]);
+ for (int j = 0; j < _gfxItemsCount; ++j)
+ _gfxItems[j].testUpdRect(_dirtyRects[i]);
+ }
+
+ for (int k = 0; k < _gfxItemsCount; ++k) {
+ GfxItem *gfxItem2 = &_gfxItems[k];
+
+ if (!gfxItem2->_updFlag)
+ continue;
+
+ if (gfxItem2->_prevFrame._spriteId != -1) {
+ bool transparent = false;
+ if (gfxItem2->_currFrame._spriteId != -1) {
+ if (gfxItem2->_flags) {
+ transparent = true;
+ } else {
+ int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ transparent = spriteResource->_transparent;
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ if (gfxItem2->_currFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || !transparent) {
+ restoreBackgroundRect(gfxItem2->_prevFrame._rect);
+ for (int l = 0; l < _gfxItemsCount; ++l)
+ _gfxItems[l].testUpdRect(gfxItem2->_prevFrame._rect);
+ }
+ }
+
+ if (gfxItem2->_currFrame._spriteId != -1) {
+ bool transparent = false;
+ if (gfxItem2->_flags) {
+ transparent = true;
+ } else {
+ int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ transparent = spriteResource->_transparent;
+ _vm->_spriteCache->release(resourceId);
+ }
+ if (gfxItem2->_prevFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || transparent) {
+ for (int l = k; l < _gfxItemsCount; ++l)
+ _gfxItems[l].testUpdRect(gfxItem2->_currFrame._rect);
+ }
+ }
+ }
+
+ for (int m = 0; m < _gfxItemsCount; ++m) {
+ GfxItem *gfxItem5 = &_gfxItems[m];
+
+ debugC(kDebugBasic, "DrawGfxItem(%d) updFlag: %d; currFrame.spriteId: %04X; updRectsCount: %d; flags: %04X; sequenceId: %08X",
+ m, gfxItem5->_updFlag, gfxItem5->_currFrame._spriteId, gfxItem5->_updRectsCount, gfxItem5->_flags, gfxItem5->_sequenceId);
+
+ if (gfxItem5->_updFlag) {
+ if (gfxItem5->_currFrame._spriteId != -1) {
+ if (gfxItem5->_flags) {
+ seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_currFrame, nullptr);
+ } else {
+ int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_currFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ seqDrawSpriteFrame(spriteResource, gfxItem5->_currFrame, nullptr);
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ } else if (gfxItem5->_updRectsCount > 0) {
+ if (gfxItem5->_flags) {
+ for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
+ seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
+ } else {
+ int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_prevFrame._spriteId;
+ SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId);
+ for (int n = 0; n < gfxItem5->_updRectsCount; ++n)
+ seqDrawSpriteFrame(spriteResource, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]);
+ _vm->_spriteCache->release(resourceId);
+ }
+ }
+ }
+
+ debugC(kDebugBasic, "GameSys::drawSprites() OK");
+}
+
+void GameSys::updateRect(const Common::Rect &r) {
+ debugC(kDebugBasic, "GameSys::updateRect() %d, %d, %d, %d [%d, %d]", r.left, r.top, r.right, r.bottom, r.width(), r.height());
+ if (r.width() > 0 && r.height() > 0) {
+ byte *pixels = (byte *)_frontSurface->getBasePtr(r.left, r.top);
+ _vm->_system->copyRectToScreen(pixels, _frontSurface->pitch, r.left, r.top,
+ r.width(), r.height());
+ }
+}
+
+void GameSys::updateScreen() {
+ debugC(kDebugBasic, "GameSys::updateScreen()");
+
+ for (uint i = 0; i < _dirtyRects.size(); ++i)
+ updateRect(_dirtyRects[i]);
+
+ if (_dirtyRects.size() > 0) {
+ _dirtyRects.clear();
+ _lastUpdateClock = 0;
+ _gameSysClock = 0;
+ }
+
+ Common::Rect dstRect, srcRect, rcSrc2;
+
+ for (int j = 0; j < _gfxItemsCount; ++j) {
+
+ GfxItem *gfxItem = &_gfxItems[j];
+
+ if (!gfxItem->_updFlag)
+ continue;
+
+ if (gfxItem->_prevFrame._spriteId == -1 ||
+ !intersectRect(srcRect, _screenRect, gfxItem->_prevFrame._rect)) {
+ if (gfxItem->_currFrame._spriteId != -1 && intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect))
+ updateRect(rcSrc2);
+ } else if (gfxItem->_currFrame._spriteId != -1 &&
+ intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect)) {
+ updateRect(srcRect);
+ updateRect(rcSrc2);
+ }
+ gfxItem->_prevFrame = gfxItem->_currFrame;
+ }
+
+ updateRect(Common::Rect(0, 0, 800, 600));
+
+ debugC(kDebugBasic, "GameSys::updateScreen() OK");
+}
+
+void GameSys::handleReqRemoveSequenceItem() {
+ if (_reqRemoveSequenceItem) {
+ int gfxIndex2;
+ _reqRemoveSequenceItem = false;
+ if (seqFind(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2))
+ _seqItems.remove_at(gfxIndex2);
+ if (seqLocateGfx(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2)) {
+ int gfxIndex2a = gfxIndex2;
+ for (GfxItem *gfxItem = &_gfxItems[gfxIndex2a];
+ gfxIndex2a < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItemSequenceId && gfxItem->_id == _removeSequenceItemValue;
+ gfxItem = &_gfxItems[gfxIndex2a])
+ ++gfxIndex2a;
+ _gfxItemsCount -= gfxIndex2a - gfxIndex2;
+ if (_gfxItemsCount != gfxIndex2)
+ memmove(&_gfxItems[gfxIndex2], &_gfxItems[gfxIndex2a], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex2));
+ }
+ }
+}
+
+void GameSys::handleReqRemoveSequenceItems() {
+ if (_removeSequenceItemsCount > 0) {
+ for (int i = 0; i < _removeSequenceItemsCount; ++i) {
+ int gfxIndex;
+ if (seqFind(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex))
+ _seqItems.remove_at(gfxIndex);
+ seqLocateGfx(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex);
+ for (GfxItem *gfxItem = &_gfxItems[gfxIndex];
+ gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItems[i]._sequenceId && gfxItem->_id == _removeSequenceItems[i]._id;
+ gfxItem = &_gfxItems[gfxIndex]) {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ if (_removeSequenceItems[i]._forceFrameReset) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ ++gfxIndex;
+ }
+ }
+ _removeSequenceItemsCount = 0;
+ }
+}
+
+void GameSys::handleReqRemoveSpriteDrawItems() {
+ if (_removeSpriteDrawItemsCount > 0) {
+ for (int j = 0; j < _removeSpriteDrawItemsCount; ++j) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
+ && gfxItem->_id == _removeSpriteDrawItems[j]._id && _removeSpriteDrawItems[j]._surface == gfxItem->_surface) {
+ gfxItem->_flags = 0;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ }
+ }
+ }
+ _removeSpriteDrawItemsCount = 0;
+ }
+}
+
+void GameSys::fatUpdateFrame() {
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame()");
+
+ int32 clockDelta = _gameSysClock - _lastUpdateClock;
+ _lastUpdateClock = _gameSysClock;
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() clockDelta: %d", clockDelta);
+
+ if (clockDelta <= 0)
+ return;
+
+ _animationsDone = true;
+
+ int duration, currFrameNum;
+
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ SequenceAnimation *animation = gfxItem->_animation;
+ if ((gfxItem->_sequenceId != -1 && animation) || gfxItem->_prevFrame._spriteId != -1 || gfxItem->_prevFrame._duration > 0) {
+ if (gfxItem->_sequenceId != -1 && !gfxItem->_updFlag) {
+ Sequence *seqItem = seqFind(gfxItem->_sequenceId, gfxItem->_id, nullptr);
+ if (!animation) {
+ gfxItem->_sequenceId = -1;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else if (!seqItem) {
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._spriteId = -1;
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ } else if ((seqItem->_flags & kSeqUnk) && clockDelta > 1) {
+ if (gfxItem->_delayTicks < clockDelta) {
+ duration = clockDelta - gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ if (gfxItem->_prevFrame._duration <= duration)
+ gfxItem->_prevFrame._duration = 1;
+ else
+ gfxItem->_prevFrame._duration -= duration;
+ } else {
+ gfxItem->_delayTicks -= clockDelta;
+ }
+ gfxItem->_updFlag = false;
+ } else if (gfxItem->_delayTicks < clockDelta) {
+ duration = clockDelta - gfxItem->_delayTicks;
+ gfxItem->_delayTicks = 0;
+ if (gfxItem->_prevFrame._duration <= duration) {
+ bool v20 = false;
+ if (gfxItem->_prevFrame._duration > 0) {
+ duration -= gfxItem->_prevFrame._duration;
+ gfxItem->_prevFrame._duration = -duration;
+ } else {
+ gfxItem->_prevFrame._duration = 0;
+ v20 = true;
+ }
+ currFrameNum = gfxItem->_currFrameNum;
+ if (animation->_framesCount > currFrameNum) {
+ while (animation->_framesCount > currFrameNum
+ && animation->frames[currFrameNum]._duration <= duration) {
+ if (animation->frames[currFrameNum]._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[currFrameNum]._soundId);
+ duration -= animation->frames[currFrameNum]._duration;
+ ++currFrameNum;
+ }
+ if (animation->_framesCount > currFrameNum)
+ gfxItem->_currFrame = animation->frames[currFrameNum++];
+ else
+ gfxItem->_currFrame = animation->frames[currFrameNum - 1];
+ if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0))
+ gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y);
+ // Update sprite scaling
+ if ((seqItem->_flags & kSeqScale) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) {
+ int v17 = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) *
+ (_backgroundImageValue4 - _backgroundImageValue2) /
+ (_backgroundImageValue3 - _backgroundImageValue1);
+ gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - v17 * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000;
+ gfxItem->_currFrame._rect.right = v17 * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left;
+ gfxItem->_currFrame._isScaled = true;
+ }
+ gfxItem->_currFrame._duration -= duration;
+ if (gfxItem->_currFrame._soundId != -1)
+ _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId);
+ gfxItem->_currFrameNum = currFrameNum;
+ gfxItem->_updFlag = true;
+ } else if (v20 && gfxItem->_prevFrame._spriteId == -1) {
+ --_gfxItemsCount;
+ if (_gfxItemsCount != i)
+ memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
+ --i;
+ } else {
+ gfxItem->_updFlag = false;
+ }
+ } else {
+ gfxItem->_prevFrame._duration -= duration;
+ gfxItem->_updFlag = false;
+ _animationsDone = false;
+ }
+ } else {
+ gfxItem->_delayTicks -= clockDelta;
+ gfxItem->_updFlag = false;
+ _animationsDone = false;
+ }
+ }
+ } else {
+ --_gfxItemsCount;
+ if (_gfxItemsCount != i)
+ memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i));
+ --i;
+ }
+ }
+
+ if (_newSpriteDrawItemsCount > 0) {
+ debugC(kDebugBasic, "_newSpriteDrawItemsCount: %d", _newSpriteDrawItemsCount);
+ for (int k = 0; k < _newSpriteDrawItemsCount; ++k) {
+ // The original was allowing a buffer overflow.
+ // In order to fit in memory, insertIndex + 1 + (_gfxItemsCount - InsertIndex) must be
+ // smaller than the size _gfxItems array (50).
+ if (_gfxItemsCount + 1 < 50) {
+ int insertIndex;
+ seqLocateGfx(-1, _newSpriteDrawItems[k]._id, &insertIndex);
+ if (_gfxItemsCount != insertIndex)
+ memmove(&_gfxItems[insertIndex + 1], &_gfxItems[insertIndex], sizeof(GfxItem) * (_gfxItemsCount - insertIndex));
+ ++_gfxItemsCount;
+ GfxItem *gfxItem = &_gfxItems[insertIndex];
+ gfxItem->_sequenceId = -1;
+ gfxItem->_id = _newSpriteDrawItems[k]._id;
+ gfxItem->_animation = nullptr;
+ gfxItem->_currFrameNum = 0;
+ gfxItem->_flags = 1;
+ gfxItem->_delayTicks = 0;
+ gfxItem->_updFlag = true;
+ gfxItem->_updRectsCount = 0;
+ gfxItem->_surface = _newSpriteDrawItems[k]._surface;
+ gfxItem->_prevFrame._duration = 0;
+ gfxItem->_prevFrame._spriteId = -1;
+ gfxItem->_prevFrame._soundId = -1;
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._isScaled = false;
+ gfxItem->_currFrame._rect = _newSpriteDrawItems[k]._rect;
+ gfxItem->_currFrame._spriteId = _newSpriteDrawItems[k]._surface ? (int32)0xCAFEBABE : -1;// TODO
+ gfxItem->_currFrame._soundId = -1;
+ _animationsDone = false;
+ }
+ }
+ _newSpriteDrawItemsCount = 0;
+ }
+
+ if (_grabSpriteChanged) {
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ GfxItem *gfxItem = &_gfxItems[i];
+ if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags
+ && gfxItem->_id == _grabSpriteId && gfxItem->_surface == _grabSpriteSurface1) {
+ gfxItem->_currFrame._duration = 0;
+ gfxItem->_currFrame._isScaled = false;
+ gfxItem->_currFrame._rect = _grabSpriteRect;
+ gfxItem->_currFrame._spriteId = _grabSpriteSurface2 ? 1 : -1;// TODO
+ gfxItem->_currFrame._soundId = -1;
+ gfxItem->_updFlag = true;
+ gfxItem->_surface = _grabSpriteSurface2;
+ _animationsDone = false;
+ break;
+ }
+ }
+ _grabSpriteChanged = false;
+ }
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() _fatSequenceItems.size(): %d", _fatSequenceItems.size());
+
+ for (uint i = 0; i < _fatSequenceItems.size(); ++i) {
+ Sequence *seqItem = &_fatSequenceItems[i];
+ if (((seqItem->_flags & kSeqSyncWait) || (seqItem->_flags & kSeqSyncExists)) && seqItem->_sequenceId2 != -1) {
+ duration = 0;
+ if (((seqItem->_flags & kSeqSyncExists) && seqLocateGfx(seqItem->_sequenceId2, seqItem->_id2, nullptr)) ||
+ updateSequenceDuration(seqItem->_sequenceId2, seqItem->_id2, &duration)) {
+ int index = -1;
+ bool found = false;
+ if (seqItem->_sequenceId2 == seqItem->_sequenceId && seqItem->_id == seqItem->_id2 &&
+ seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
+ _seqItems[index] = *seqItem;
+ found = true;
+ } else if (_seqItems.size() < 50) {
+ index = _seqItems.size();
+ _seqItems.push_back(*seqItem);
+ found = true;
+ }
+ if (found) {
+ _animationsDone = false;
+ seqRemoveGfx(seqItem->_sequenceId2, seqItem->_id2);
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ _fatSequenceItems.remove_at(i);
+ --i;
+ seqInsertGfx(index, duration);
+ }
+ }
+ } else {
+ if (seqItem->_totalDuration < clockDelta) {
+ int index;
+ bool found = false;
+ duration = clockDelta - seqItem->_totalDuration;
+ seqItem->_totalDuration = 0;
+ if (seqFind(seqItem->_sequenceId, seqItem->_id, &index)) {
+ _seqItems[index] = *seqItem;
+ found = true;
+ } else if (_seqItems.size() < 50) {
+ index = _seqItems.size();
+ _seqItems.push_back(*seqItem);
+ found = true;
+ }
+ if (found) {
+ _animationsDone = false;
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ _fatSequenceItems.remove_at(i);
+ --i;
+ seqInsertGfx(index, duration - 1);
+ }
+ } else {
+ seqItem->_totalDuration -= clockDelta;
+ }
+ }
+ }
+
+ debugC(kDebugBasic, "GameSys::fatUpdateFrame() _seqItems.size(): %d", _seqItems.size());
+
+ for (uint i = 0; i < _seqItems.size(); ++i) {
+ Sequence *seqItem = &_seqItems[i];
+ if (seqLocateGfx(seqItem->_sequenceId, seqItem->_id, nullptr)) {
+ updateAnimationsStatus(seqItem->_sequenceId, seqItem->_id);
+ if (seqItem->_flags & kSeqLoop) {
+ int gfxDuration;
+ if (updateSequenceDuration(seqItem->_sequenceId, seqItem->_id, &gfxDuration)) {
+ seqRemoveGfx(seqItem->_sequenceId, seqItem->_id);
+ seqInsertGfx(i, gfxDuration);
+ }
+ _animationsDone = false;
+ }
+ } else {
+ _seqItems.remove_at(i);
+ --i;
+ }
+ }
+}
+
+void GameSys::fatUpdate() {
+ debugC(kDebugBasic, "GameSys::fatUpdate() _gfxItemsCount: %d", _gfxItemsCount);
+
+ for (int i = 0; i < _gfxItemsCount; ++i) {
+ _gfxItems[i]._updFlag = false;
+ _gfxItems[i]._updRectsCount = 0;
+ }
+
+ handleReqRemoveSequenceItem();
+ handleReqRemoveSequenceItems();
+ handleReqRemoveSpriteDrawItems();
+
+ fatUpdateFrame();
+}
+
+void GameSys::updatePlaySounds() {
+ for (uint i = 0; i < _soundIds.size(); ++i)
+ _vm->playSound(_soundIds[i], false);
+ _soundIds.clear();
+}
+
+bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2) {
+ if (r1.intersects(r2)) {
+ intersectingRect = r1.findIntersectingRect(r2);
+ return true;
+ } else
+ return false;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/gamesys.h b/engines/gnap/gamesys.h
new file mode 100644
index 0000000000..b9752bde06
--- /dev/null
+++ b/engines/gnap/gamesys.h
@@ -0,0 +1,213 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GAMESYS_H
+#define GNAP_GAMESYS_H
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+#include "common/array.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+
+namespace Gnap {
+
+const int kMaxSequenceItems = 40;
+const int kMaxSpriteDrawItems = 30;
+const int kMaxSoundIds = 50;
+const int kMaxSeqItems = 50;
+const int kMaxUpdRects = 20;
+const int kMaxGfxItems = 50;
+const int kMaxAnimations = 12;
+
+enum {
+ kSeqNone = 0x00,
+ kSeqScale = 0x01, // Enable scaling
+ kSeqLoop = 0x02, // Loop
+ kSeqUnk = 0x04, // Unknown
+ kSeqSyncWait = 0x08, // Start if other sequence is done
+ kSeqSyncExists = 0x20 // Start if other sequence exists
+};
+
+struct Sequence {
+ int32 _sequenceId;
+ int32 _id;
+ int32 _sequenceId2;
+ int32 _id2;
+ uint32 _flags;
+ int32 _totalDuration;
+ int16 _x, _y;
+};
+
+struct SpriteDrawItem {
+ int _id;
+ Common::Rect _rect;
+ Graphics::Surface *_surface;
+};
+
+struct RemoveSequenceItem {
+ int _sequenceId;
+ int _id;
+ bool _forceFrameReset;
+};
+
+struct RemoveSpriteDrawItem {
+ int _id;
+ Graphics::Surface *_surface;
+};
+
+struct GfxItem {
+ int _sequenceId;
+ int _id;
+ int _flags;
+ SequenceAnimation *_animation;
+ int _currFrameNum;
+ int _delayTicks;
+ bool _updFlag;
+ int _updRectsCount;
+ Graphics::Surface *_surface;
+ Common::Rect _updRects[kMaxUpdRects];
+ SequenceFrame _prevFrame;
+ SequenceFrame _currFrame;
+ void testUpdRect(const Common::Rect &updRect);
+};
+
+struct Animation {
+ int _sequenceId;
+ int _id;
+ int _status;
+};
+
+class GameSys {
+public:
+ GameSys(GnapEngine *vm);
+ ~GameSys();
+ void insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y);
+ void insertDirtyRect(const Common::Rect &rect);
+ void removeSequence(int sequenceId, int id, bool resetFl);
+ void invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2);
+ void requestClear2(bool resetFl);
+ void requestClear1();
+ void requestRemoveSequence(int sequenceId, int id);
+ void waitForUpdate();
+ int isSequenceActive(int sequenceId, int id);
+ void setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7);
+ void setScaleValues(int a1, int a2, int a3, int a4);
+ void insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id);
+ void removeSpriteDrawItem(Graphics::Surface *surface, int id);
+ void drawSpriteToBackground(int x, int y, int resourceId);
+ Graphics::Surface *allocSurface(int width, int height);
+ Graphics::Surface *createSurface(int resourceId);
+ void drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId);
+ void drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text);
+ int getTextHeight(const char *text);
+ int getTextWidth(const char *text);
+ void fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b);
+ void setAnimation(int sequenceId, int id, int animationIndex);
+ int getAnimationStatus(int animationIndex);
+ int getSpriteWidthById(int resourceId);
+ int getSpriteHeightById(int resourceId);
+ Graphics::Surface *loadBitmap(int resourceId);
+ void drawBitmap(int resourceId);
+public:
+ GnapEngine *_vm;
+
+ Common::Array<Common::Rect> _dirtyRects;
+
+ SpriteDrawItem _newSpriteDrawItems[kMaxSpriteDrawItems];
+ int _newSpriteDrawItemsCount;
+
+ RemoveSequenceItem _removeSequenceItems[kMaxSequenceItems];
+ int _removeSequenceItemsCount;
+
+ RemoveSpriteDrawItem _removeSpriteDrawItems[kMaxSpriteDrawItems];
+ int _removeSpriteDrawItemsCount;
+
+ int _grabSpriteId;
+ Common::Rect _grabSpriteRect;
+ bool _grabSpriteChanged;
+ Graphics::Surface *_grabSpriteSurface1, *_grabSpriteSurface2;
+
+ bool _reqRemoveSequenceItem;
+ int _removeSequenceItemSequenceId, _removeSequenceItemValue;
+
+ Common::Array<int> _soundIds;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ Common::Array<Sequence> _seqItems;
+ Common::Array<Sequence> _fatSequenceItems;
+
+ GfxItem _gfxItems[kMaxGfxItems];
+ int _gfxItemsCount;
+
+ Animation _animations[kMaxAnimations];
+ int _animationsCount;
+
+ int _backgroundImageValue3, _backgroundImageValue1;
+ int _backgroundImageValue4, _backgroundImageValue2;
+
+ int32 _gameSysClock, _lastUpdateClock;
+ bool _animationsDone;
+
+
+ Graphics::Surface *_backgroundSurface;
+ Graphics::Surface *_frontSurface;
+ Common::Rect _screenRect;
+
+ Sequence *seqFind(int sequenceId, int id, int *outIndex);
+ int seqLocateGfx(int sequenceId, int id, int *outGfxIndex);
+ void seqInsertGfx(int index, int duration);
+ void seqRemoveGfx(int sequenceId, int id);
+ bool updateSequenceDuration(int sequenceId, int id, int *outDuration);
+ void updateAnimationsStatus(int sequenceId, int id);
+
+ void restoreBackgroundRect(const Common::Rect &rect);
+
+ void blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface,
+ Common::Rect &sourceRect, bool transparent);
+ void blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels,
+ int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent);
+ void blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect,
+ Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette);
+
+ void seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect);
+ void seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect);
+
+ void drawSprites();
+ void updateRect(const Common::Rect &r);
+ void updateScreen();
+
+ void handleReqRemoveSequenceItem();
+ void handleReqRemoveSequenceItems();
+ void handleReqRemoveSpriteDrawItems();
+ void fatUpdateFrame();
+ void fatUpdate();
+ void updatePlaySounds();
+
+};
+
+bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2);
+
+} // End of namespace Gnap
+
+#endif // GNAP_GAMESYS_H
diff --git a/engines/gnap/gnap.cpp b/engines/gnap/gnap.cpp
new file mode 100644
index 0000000000..6a03bf8eb0
--- /dev/null
+++ b/engines/gnap/gnap.cpp
@@ -0,0 +1,1239 @@
+/* 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.
+ *
+ */
+
+#include "graphics/cursorman.h"
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/sound.h"
+
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/timer.h"
+
+#include "engines/util.h"
+
+namespace Gnap {
+
+static const int kCursors[] = {
+ LOOK_CURSOR,
+ GRAB_CURSOR,
+ TALK_CURSOR,
+ PLAT_CURSOR
+};
+
+static const int kDisabledCursors[] = {
+ NOLOOK_CURSOR,
+ NOGRAB_CURSOR,
+ NOTALK_CURSOR,
+ NOPLAT_CURSOR
+};
+
+static const char *kCursorNames[] = {
+ "LOOK_CURSOR",
+ "GRAB_CURSOR",
+ "TALK_CURSOR",
+ "PLAT_CURSOR",
+ "NOLOOK_CURSOR",
+ "NOGRAB_CURSOR",
+ "NOTALK_CURSOR",
+ "NOPLAT_CURSOR",
+ "EXIT_L_CURSOR",
+ "EXIT_R_CURSOR",
+ "EXIT_U_CURSOR",
+ "EXIT_D_CURSOR",
+ "EXIT_NE_CURSOR",
+ "EXIT_NW_CURSOR",
+ "EXIT_SE_CURSOR",
+ "EXIT_SW_CURSOR",
+ "WAIT_CURSOR"
+};
+
+
+static const int kCursorSpriteIds[30] = {
+ 0x005, 0x008, 0x00A, 0x004, 0x009, 0x003,
+ 0x006, 0x007, 0x00D, 0x00F, 0x00B, 0x00C,
+ 0x019, 0x01C, 0x015, 0x014, 0x010, 0x01A,
+ 0x018, 0x013, 0x011, 0x012, 0x01B, 0x016,
+ 0x017, 0x01D, 0x01E, 0x01F, 0x76A, 0x76B
+};
+
+static const char *kSceneNames[] = {
+ "open", "pigpn", "truck", "creek", "mafrm", "frbrn", "inbrn", "crash",
+ "porch", "barbk", "kitch", "bar", "juke", "wash", "john", "jkbox",
+ "brawl", "stret", "frtoy", "intoy", "frgro", "park", "cash", "ingro",
+ "frcir", "booth", "circ", "outcl", "incln", "monk", "elcir", "beer",
+ "pig2", "trk2", "creek", "frbrn", "inbrn", "mafrm", "infrm", "efair",
+ "fair", "souv", "chick", "ship", "kiss", "disco", "boot", "can",
+ "can2", "drive", "tung", "puss", "space", "phone", "can3"
+};
+
+GnapEngine::GnapEngine(OSystem *syst, const ADGameDescription *gd) :
+ Engine(syst), _gameDescription(gd) {
+
+ _random = new Common::RandomSource("gnap");
+ DebugMan.addDebugChannel(kDebugBasic, "basic", "Basic debug level");
+
+ Engine::syncSoundSettings();
+
+ _exe = nullptr;
+ _dat = nullptr;
+ _spriteCache = nullptr;
+ _soundCache = nullptr;
+ _sequenceCache = nullptr;
+ _gameSys = nullptr;
+ _soundMan = nullptr;
+ _debugger = nullptr;
+ _gnap = nullptr;
+ _plat = nullptr;
+ _font = nullptr;
+ _scene = nullptr;
+ _music = nullptr;
+ _tempThumbnail = nullptr;
+ _menuBackgroundSurface = nullptr;
+ _menuQuitQuerySprite = nullptr;
+ _largeSprite = nullptr;
+ _menuSaveLoadSprite = nullptr;
+ _menuSprite2 = nullptr;
+ _menuSprite1 = nullptr;
+ _spriteHandle = nullptr;
+ _cursorSprite = nullptr;
+ _pauseSprite = nullptr;
+ _backgroundSurface = nullptr;
+
+ _wasSavegameLoaded = false;
+ _isWaiting = false;
+ _sceneWaiting = false;
+ _menuDone = false;
+ _sceneDone = false;
+ _isLeavingScene = false;
+ _isStockDatLoaded = false;
+ _gameDone = false;
+ _isPaused = false;
+ _sceneSavegameLoaded = false;
+
+ for (int i = 0; i < kMaxTimers; ++i)
+ _savedTimers[i] = _timers[i] = 0;
+
+ _mousePos = Common::Point(0, 0);
+ _currGrabCursorX = _currGrabCursorY = 0;
+
+ _idleTimerIndex = -1;
+ _menuStatus = 0;
+ _menuSpritesIndex = -1;
+ _savegameIndex = -1;
+ _gridMinX = 0;
+ _gridMinY = 0;
+ _gridMaxX = 0;
+ _gridMaxY = 0;
+ _toyUfoNextSequenceId = -1;
+ _toyUfoSequenceId = -1;
+ _toyUfoId = -1;
+ _toyUfoActionStatus = -1;
+ _toyUfoX = 0;
+ _toyUfoY = 0;
+ _s18GarbageCanPos = 0;
+
+ for (int i = 0; i < 7; i++)
+ _savegameSprites[i] = nullptr;
+ for (int i = 0; i < 30; i++)
+ _menuInventorySprites[i] = nullptr;
+
+ _newSceneNum = 0;
+ _inventory = 0;
+ _gameFlags = 0;
+ _hotspotsCount = 0;
+ _sceneClickedHotspot = -1;
+ _newCursorValue = 0;
+ _cursorValue = 0;
+ _verbCursor = 0;
+ _cursorIndex = -1;
+ _leftClickMouseX = 0;
+ _leftClickMouseY = 0;
+ _grabCursorSprite = nullptr;
+ _grabCursorSpriteIndex = 0;
+ _newGrabCursorSpriteIndex = 0;
+ _fullScreenSprite = nullptr;
+ _fullScreenSpriteId = 0;
+ _deviceX1 = 0;
+ _deviceY1 = 0;
+ _soundTimerIndexA = 0;
+ _soundTimerIndexB = 0;
+ _soundTimerIndexC = 0;
+ _loadGameSlot = -1;
+ _lastUpdateClock = 0;
+ _prevSceneNum = -1;
+ _currentSceneNum = -1;
+}
+
+GnapEngine::~GnapEngine() {
+ delete _random;
+ delete _music;
+ delete _tempThumbnail;
+}
+
+Common::Error GnapEngine::run() {
+ // Initialize the graphics mode to RGBA8888
+#if defined(SCUMM_BIG_ENDIAN)
+ Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24);
+#else
+ Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+#endif
+ initGraphics(800, 600, true, &format);
+
+ // We do not support color conversion yet
+ if (_system->getScreenFormat() != format)
+ return Common::kUnsupportedColorMode;
+
+ _lastUpdateClock = 0;
+
+ // >>>>> Variable initialization
+ _cursorIndex = -1;
+ _verbCursor = 1;
+
+ if (ConfMan.hasKey("save_slot"))
+ _loadGameSlot = ConfMan.getInt("save_slot");
+
+ invClear();
+ clearFlags();
+
+ _grabCursorSprite = nullptr;
+ _newGrabCursorSpriteIndex = -1;
+ _backgroundSurface = nullptr;
+ _isStockDatLoaded = false;
+ _gameDone = false;
+ _isPaused = false;
+ _pauseSprite = nullptr;
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ _exe = new Common::PEResources();
+ if (!_exe->loadFromEXE("ufos.exe"))
+ error("Could not load ufos.exe");
+
+#ifdef USE_FREETYPE2
+ Common::SeekableReadStream *stream = _exe->getResource(Common::kPEFont, 2000);
+ _font = Graphics::loadTTFFont(*stream, 24);
+ if (!_font)
+ warning("Unable to load font");
+ delete stream;
+#else
+ _font = nullptr;
+#endif
+
+ _dat = new DatManager();
+ _spriteCache = new SpriteCache(_dat);
+ _soundCache = new SoundCache(_dat);
+ _sequenceCache = new SequenceCache(_dat);
+ _gameSys = new GameSys(this);
+ _soundMan = new SoundMan(this);
+ _debugger = new Debugger(this);
+ _gnap = new PlayerGnap(this);
+ _plat = new PlayerPlat(this);
+
+ _menuBackgroundSurface = nullptr;
+
+ initGlobalSceneVars();
+ mainLoop();
+
+ delete _plat;
+ delete _gnap;
+ delete _soundMan;
+ delete _gameSys;
+ delete _sequenceCache;
+ delete _soundCache;
+ delete _spriteCache;
+ delete _dat;
+ delete _debugger;
+ delete _font;
+ delete _exe;
+
+ return Common::kNoError;
+}
+
+void GnapEngine::updateEvents() {
+ Common::Event event;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ // Check for debugger
+ if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) {
+ // Attach to the debugger
+ _debugger->attach();
+ _debugger->onFrame();
+ }
+
+ _keyPressState[event.kbd.keycode] = true;
+ _keyDownState[event.kbd.keycode] = true;
+ break;
+ case Common::EVENT_KEYUP:
+ _keyDownState[event.kbd.keycode] = false;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mousePos = event.mouse;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _mouseButtonState._left = false;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _leftClickMouseX = event.mouse.x;
+ _leftClickMouseY = event.mouse.y;
+ _mouseButtonState._left = true;
+ _mouseClickState._left = true;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _mouseButtonState._right = false;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButtonState._right = true;
+ _mouseClickState._right = true;
+ break;
+ case Common::EVENT_QUIT:
+ quitGame();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void GnapEngine::gameUpdateTick() {
+ updateEvents();
+
+ if (shouldQuit()) {
+ _gameDone = true;
+ _sceneDone = true;
+ }
+
+ int currClock = _system->getMillis();
+ if (currClock >= _lastUpdateClock + 66) {
+ _gameSys->fatUpdate();
+ _gameSys->drawSprites();
+ _gameSys->updateScreen();
+ _gameSys->updatePlaySounds();
+ _gameSys->_gameSysClock++;
+ updateTimers();
+ _lastUpdateClock = currClock;
+ }
+
+ _soundMan->update();
+ _system->updateScreen();
+ _system->delayMillis(5);
+}
+
+void GnapEngine::saveTimers() {
+ for (int i = 0; i < kMaxTimers; ++i )
+ _savedTimers[i] = _timers[i];
+}
+
+void GnapEngine::restoreTimers() {
+ for (int i = 0; i < kMaxTimers; ++i )
+ _timers[i] = _savedTimers[i];
+}
+
+void GnapEngine::pauseGame() {
+ if (!_isPaused) {
+ saveTimers();
+ hideCursor();
+ setGrabCursorSprite(-1);
+ _pauseSprite = _gameSys->createSurface(0x1076C);
+ _gameSys->insertSpriteDrawItem(_pauseSprite, (800 - _pauseSprite->w) / 2, (600 - _pauseSprite->h) / 2, 356);
+ _lastUpdateClock = 0;
+ gameUpdateTick();
+ playMidi("pause.mid");
+ _isPaused = true;
+ }
+}
+
+void GnapEngine::resumeGame() {
+ if (_isPaused) {
+ restoreTimers();
+ _gameSys->removeSpriteDrawItem(_pauseSprite, 356);
+ _lastUpdateClock = 0;
+ gameUpdateTick();
+ deleteSurface(&_pauseSprite);
+ stopMidi();
+ _isPaused = false;
+ clearAllKeyStatus1();
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+ showCursor();
+ _gameSys->_gameSysClock = 0;
+ _gameSys->_lastUpdateClock = 0;
+ }
+}
+
+void GnapEngine::updatePause() {
+ while (_isPaused && !_gameDone) {
+ gameUpdateTick();
+ if (isKeyStatus1(Common::KEYCODE_p)) {
+ clearKeyStatus1(Common::KEYCODE_p);
+ resumeGame();
+ }
+ }
+}
+
+int GnapEngine::getRandom(int max) {
+ return _random->getRandomNumber(max - 1);
+}
+
+int GnapEngine::readSavegameDescription(int savegameNum, Common::String &description) {
+ description = Common::String::format("Savegame %d", savegameNum);
+ return 0;
+}
+
+int GnapEngine::loadSavegame(int savegameNum) {
+ return 1;
+}
+
+void GnapEngine::delayTicks(int val, int idx = 0, bool updateCursor = false) {
+ int startTick = _timers[idx];
+
+ _timers[idx] = val;
+
+ while (_timers[idx] && !_gameDone) {
+ gameUpdateTick();
+
+ if (updateCursor)
+ updateGrabCursorSprite(0, 0);
+ }
+
+ startTick -= _timers[idx];
+ if (startTick < 0)
+ startTick = 0;
+
+ _timers[idx] = startTick;
+}
+
+void GnapEngine::delayTicksA(int val, int idx) {
+ delayTicks(val, idx);
+}
+
+void GnapEngine::delayTicksCursor(int val) {
+ delayTicks(val, 0, true);
+}
+
+void GnapEngine::setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags,
+ int16 walkX, int16 walkY) {
+ _hotspots[index]._rect = Common::Rect(x1, y1, x2, y2);
+ _hotspots[index]._flags = flags;
+ _hotspotsWalkPos[index] = Common::Point(walkX, walkY);
+}
+
+int GnapEngine::getHotspotIndexAtPos(Common::Point pos) {
+ for (int i = 0; i < _hotspotsCount; ++i) {
+ if (!_hotspots[i].isFlag(SF_DISABLED) && _hotspots[i].isPointInside(pos))
+ return i;
+ }
+ return -1;
+}
+
+void GnapEngine::updateCursorByHotspot() {
+ if (!_isWaiting) {
+ int hotspotIndex = getHotspotIndexAtPos(_mousePos);
+
+ if (_debugger->_showHotspotNumber) {
+ // NOTE This causes some display glitches
+ char t[256];
+ sprintf(t, "hotspot = %2d", hotspotIndex);
+ if (!_font)
+ _gameSys->fillSurface(nullptr, 10, 10, 80, 16, 0, 0, 0);
+ else
+ _gameSys->fillSurface(nullptr, 8, 9, _font->getStringWidth(t) + 10, _font->getFontHeight() + 2, 0, 0, 0);
+ _gameSys->drawTextToSurface(nullptr, 10, 10, 255, 255, 255, t);
+ }
+
+ if (hotspotIndex < 0)
+ setCursor(kDisabledCursors[_verbCursor]);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_L_CURSOR)
+ setCursor(EXIT_L_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_R_CURSOR)
+ setCursor(EXIT_R_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_U_CURSOR)
+ setCursor(EXIT_U_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_D_CURSOR)
+ setCursor(EXIT_D_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NE_CURSOR)
+ setCursor(EXIT_NE_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NW_CURSOR)
+ setCursor(EXIT_NW_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SE_CURSOR)
+ setCursor(EXIT_SE_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SW_CURSOR)
+ setCursor(EXIT_SW_CURSOR);
+ else if (_hotspots[hotspotIndex]._flags & (1 << _verbCursor))
+ setCursor(kCursors[_verbCursor]);
+ else
+ setCursor(kDisabledCursors[_verbCursor]);
+ }
+ // Update platypus hotspot
+ _hotspots[0]._rect = Common::Rect(_gridMinX + 75 * _plat->_pos.x - 30, _gridMinY + 48 * _plat->_pos.y - 100
+ , _gridMinX + 75 * _plat->_pos.x + 30, _gridMinY + 48 * _plat->_pos.y);
+}
+
+int GnapEngine::getClickedHotspotId() {
+ int result = -1;
+ if (_isWaiting)
+ _mouseClickState._left = false;
+ else if (_mouseClickState._left) {
+ int hotspotIndex = getHotspotIndexAtPos(Common::Point(_leftClickMouseX, _leftClickMouseY));
+ if (hotspotIndex >= 0) {
+ _mouseClickState._left = false;
+ _timers[3] = 300;
+ result = hotspotIndex;
+ }
+ }
+ return result;
+}
+
+int GnapEngine::getInventoryItemSpriteNum(int index) {
+ return kCursorSpriteIds[index];
+}
+
+void GnapEngine::updateMouseCursor() {
+ if (_mouseClickState._right) {
+ // Switch through the verb cursors
+ _mouseClickState._right = false;
+ _timers[3] = 300;
+ _verbCursor = (_verbCursor + 1) % 4;
+ if (!isFlag(kGFPlatypus) && _verbCursor == PLAT_CURSOR && _cursorValue == 1)
+ _verbCursor = (_verbCursor + 1) % 4;
+ if (!_isWaiting)
+ setCursor(kDisabledCursors[_verbCursor]);
+ setGrabCursorSprite(-1);
+ }
+ if (_isWaiting && ((_gnap->_actionStatus < 0 && _plat->_actionStatus < 0) || _sceneWaiting)) {
+ setCursor(kDisabledCursors[_verbCursor]);
+ showCursor();
+ _isWaiting = false;
+ } else if (!_isWaiting && (_gnap->_actionStatus >= 0 || _plat->_actionStatus >= 0) && !_sceneWaiting) {
+ setCursor(WAIT_CURSOR);
+ hideCursor();
+ _isWaiting = true;
+ }
+}
+
+void GnapEngine::setVerbCursor(int verbCursor) {
+ _verbCursor = verbCursor;
+ if (!_isWaiting)
+ setCursor(kDisabledCursors[_verbCursor]);
+}
+
+void GnapEngine::setCursor(int cursorIndex) {
+ if (_cursorIndex != cursorIndex) {
+ const char *cursorName = kCursorNames[cursorIndex];
+ Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, Common::WinResourceID(cursorName));
+ if (cursorGroup) {
+ Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor;
+ CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(),
+ cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
+ CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
+ delete cursorGroup;
+ }
+ _cursorIndex = cursorIndex;
+ }
+}
+
+void GnapEngine::showCursor() {
+ CursorMan.showMouse(true);
+}
+
+void GnapEngine::hideCursor() {
+ CursorMan.showMouse(false);
+}
+
+void GnapEngine::setGrabCursorSprite(int index) {
+ freeGrabCursorSprite();
+ if (index >= 0) {
+ createGrabCursorSprite(makeRid(1, kCursorSpriteIds[index]));
+ setVerbCursor(GRAB_CURSOR);
+ }
+ _grabCursorSpriteIndex = index;
+}
+
+void GnapEngine::createGrabCursorSprite(int spriteId) {
+ _grabCursorSprite = _gameSys->createSurface(spriteId);
+ _gameSys->insertSpriteDrawItem(_grabCursorSprite,
+ _mousePos.x - (_grabCursorSprite->w / 2),
+ _mousePos.y - (_grabCursorSprite->h / 2),
+ 300);
+ delayTicks(5);
+}
+
+void GnapEngine::freeGrabCursorSprite() {
+ if (_grabCursorSprite) {
+ _gameSys->removeSpriteDrawItem(_grabCursorSprite, 300);
+ _gameSys->removeSpriteDrawItem(_grabCursorSprite, 301);
+ delayTicks(5);
+ deleteSurface(&_grabCursorSprite);
+ }
+}
+
+void GnapEngine::updateGrabCursorSprite(int x, int y) {
+ if (_grabCursorSprite) {
+ int newGrabCursorX = _mousePos.x - (_grabCursorSprite->w / 2) - x;
+ int newGrabCursorY = _mousePos.y - (_grabCursorSprite->h / 2) - y;
+ if (_currGrabCursorX != newGrabCursorX || _currGrabCursorY != newGrabCursorY) {
+ _currGrabCursorX = newGrabCursorX;
+ _currGrabCursorY = newGrabCursorY;
+ Common::Rect rect(newGrabCursorX, newGrabCursorY,
+ newGrabCursorX + _grabCursorSprite->w, newGrabCursorY + _grabCursorSprite->h);
+ _gameSys->invalidateGrabCursorSprite(300, rect, _grabCursorSprite, _grabCursorSprite);
+ }
+ }
+}
+
+void GnapEngine::invClear() {
+ _inventory = 0;
+}
+
+void GnapEngine::invAdd(int itemId) {
+ _inventory |= (1 << itemId);
+}
+
+void GnapEngine::invRemove(int itemId) {
+ _inventory &= ~(1 << itemId);
+}
+
+bool GnapEngine::invHas(int itemId) {
+ return (_inventory & (1 << itemId)) != 0;
+}
+
+void GnapEngine::clearFlags() {
+ _gameFlags = 0;
+}
+
+void GnapEngine::setFlag(int num) {
+ _gameFlags |= (1 << num);
+}
+
+void GnapEngine::clearFlag(int num) {
+ _gameFlags &= ~(1 << num);
+}
+
+bool GnapEngine::isFlag(int num) {
+ return (_gameFlags & (1 << num)) != 0;
+}
+
+Graphics::Surface *GnapEngine::addFullScreenSprite(int resourceId, int id) {
+ _fullScreenSpriteId = id;
+ _fullScreenSprite = _gameSys->createSurface(resourceId);
+ _gameSys->insertSpriteDrawItem(_fullScreenSprite, 0, 0, id);
+ return _fullScreenSprite;
+}
+
+void GnapEngine::removeFullScreenSprite() {
+ _gameSys->removeSpriteDrawItem(_fullScreenSprite, _fullScreenSpriteId);
+ deleteSurface(&_fullScreenSprite);
+}
+
+void GnapEngine::showFullScreenSprite(int resourceId) {
+ hideCursor();
+ setGrabCursorSprite(-1);
+ addFullScreenSprite(resourceId, 256);
+ while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE)
+ && !isKeyStatus1(Common::KEYCODE_SPACE) && !isKeyStatus1(Common::KEYCODE_RETURN) && !_gameDone) {
+ gameUpdateTick();
+ }
+ _mouseClickState._left = false;
+ clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ clearKeyStatus1(Common::KEYCODE_RETURN);
+ clearKeyStatus1(Common::KEYCODE_SPACE);
+ removeFullScreenSprite();
+ showCursor();
+}
+
+void GnapEngine::queueInsertDeviceIcon() {
+ _gameSys->insertSequence(0x10849, 20, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1);
+}
+
+void GnapEngine::insertDeviceIconActive() {
+ _gameSys->insertSequence(0x1084A, 21, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1);
+}
+
+void GnapEngine::removeDeviceIconActive() {
+ _gameSys->removeSequence(0x1084A, 21, true);
+}
+
+void GnapEngine::setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2) {
+ _deviceX1 = x1;
+ _deviceY1 = y1;
+ int deviceX2 = x2;
+ int deviceY2 = y2;
+ if (x1 == -1)
+ _deviceX1 = 730;
+ if (x2 == -1)
+ deviceX2 = 780;
+ if (y1 == -1)
+ _deviceY1 = 14;
+ if (y2 == -1)
+ deviceY2 = 79;
+
+ _hotspots[hotspotIndex]._rect = Common::Rect(_deviceX1, _deviceY1, deviceX2, deviceY2);
+ _hotspots[hotspotIndex]._flags = SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+}
+
+int GnapEngine::getSequenceTotalDuration(int resourceId) {
+ SequenceResource *sequenceResource = _sequenceCache->get(resourceId);
+ int maxValue = 0;
+ for (int i = 0; i < sequenceResource->_animationsCount; ++i) {
+ SequenceAnimation *animation = &sequenceResource->_animations[i];
+ if (animation->_additionalDelay + animation->_maxTotalDuration > maxValue)
+ maxValue = animation->_additionalDelay + animation->_maxTotalDuration;
+ }
+ int totalDuration = maxValue + sequenceResource->_totalDuration;
+ _sequenceCache->release(resourceId);
+ return totalDuration;
+}
+
+bool GnapEngine::isSoundPlaying(int resourceId) {
+ return _soundMan->isSoundPlaying(resourceId);
+}
+
+void GnapEngine::playSound(int resourceId, bool looping) {
+ debugC(kDebugBasic, "playSound(%08X, %d)", resourceId, looping);
+ _soundMan->playSound(resourceId, looping);
+}
+
+void GnapEngine::stopSound(int resourceId) {
+ _soundMan->stopSound(resourceId);
+}
+
+void GnapEngine::setSoundVolume(int resourceId, int volume) {
+ _soundMan->setSoundVolume(resourceId, volume);
+}
+
+void GnapEngine::updateTimers() {
+ for (int i = 0; i < kMaxTimers; ++i)
+ if (_timers[i] > 0)
+ --_timers[i];
+}
+
+void GnapEngine::initGameFlags(int num) {
+ invClear();
+ invAdd(kItemMagazine);
+ switch (num) {
+ case 1:
+ setFlag(kGFPlatypusTalkingToAssistant);
+ break;
+ case 2:
+ clearFlags();
+ break;
+ case 3:
+ invAdd(kItemDiceQuarterHole);
+ clearFlags();
+ break;
+ case 4:
+ invAdd(kItemDiceQuarterHole);
+ invAdd(kItemHorn);
+ invAdd(kItemLightbulb);
+ clearFlags();
+ setFlag(kGFPlatypus);
+ setFlag(kGFMudTaken);
+ setFlag(kGFNeedleTaken);
+ setFlag(kGFTwigTaken);
+ setFlag(kGFUnk04);
+ setFlag(kGFKeysTaken);
+ setFlag(kGFGrassTaken);
+ setFlag(kGFBarnPadlockOpen);
+ break;
+ }
+}
+
+void GnapEngine::loadStockDat() {
+ if (!_isStockDatLoaded) {
+ _isStockDatLoaded = true;
+ _dat->open(1, "stock_n.dat");
+ // The pre-loading of data is skipped as it's no longer required on modern hardware
+ }
+}
+
+void GnapEngine::mainLoop() {
+ _newCursorValue = 1;
+ _cursorValue = -1;
+ _newSceneNum = 0;
+ _currentSceneNum = 55;
+ _prevSceneNum = 55;
+ invClear();
+ clearFlags();
+ _grabCursorSpriteIndex = -1;
+ _grabCursorSprite = nullptr;
+
+ loadStockDat();
+
+ if (_loadGameSlot != -1) {
+ // Load a savegame
+ int slot = _loadGameSlot;
+ _loadGameSlot = -1;
+ loadGameState(slot);
+ _wasSavegameLoaded = true;
+
+ showCursor();
+ }
+
+ while (!_gameDone) {
+ debugC(kDebugBasic, "New scene: %d", _newSceneNum);
+
+ _prevSceneNum = _currentSceneNum;
+ _currentSceneNum = _newSceneNum;
+
+ debugC(kDebugBasic, "GnapEngine::mainLoop() _prevSceneNum: %d; _currentSceneNum: %d", _prevSceneNum, _currentSceneNum);
+
+ if (_newCursorValue != _cursorValue) {
+ debugC(kDebugBasic, "_newCursorValue: %d", _newCursorValue);
+ _cursorValue = _newCursorValue;
+ if (!_wasSavegameLoaded)
+ initGameFlags(_cursorValue);
+ }
+
+ _sceneSavegameLoaded = _wasSavegameLoaded;
+ _wasSavegameLoaded = false;
+
+ initScene();
+
+ runSceneLogic();
+ afterScene();
+
+ _soundMan->stopAll();
+
+ // Force purge all resources
+ _sequenceCache->purge(true);
+ _soundCache->purge(true);
+ _spriteCache->purge(true);
+ }
+
+ if (_backgroundSurface)
+ deleteSurface(&_backgroundSurface);
+
+ _dat->close(1);
+}
+
+void GnapEngine::initScene() {
+ Common::String datFilename;
+
+ _isLeavingScene = false;
+ _sceneDone = false;
+ _newSceneNum = 55;
+ _gnap->_actionStatus = -1;
+ _plat->_actionStatus = -1;
+ _gnap->initBrainPulseRndValue();
+ hideCursor();
+ clearAllKeyStatus1();
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+ _sceneClickedHotspot = -1;
+
+ datFilename = Common::String::format("%s_n.dat", kSceneNames[_currentSceneNum]);
+
+ debugC(kDebugBasic, "GnapEngine::initScene() datFilename: %s", datFilename.c_str());
+
+ _dat->open(0, datFilename.c_str());
+
+ int backgroundId = initSceneLogic();
+
+ if (!_backgroundSurface) {
+ if (_currentSceneNum != 0)
+ _backgroundSurface = _gameSys->loadBitmap(makeRid(1, 0x8AA));
+ else
+ _backgroundSurface = _gameSys->loadBitmap(makeRid(0, backgroundId));
+ _gameSys->setBackgroundSurface(_backgroundSurface, 0, 500, 1, 1000);
+ }
+
+ if (_currentSceneNum != 0 && _currentSceneNum != 16 && _currentSceneNum != 47 &&
+ _currentSceneNum != 48 && _currentSceneNum != 54) {
+ _gameSys->drawBitmap(backgroundId);
+ }
+
+ if ((_cursorValue == 4 && isFlag(kGFGnapControlsToyUFO)) || _currentSceneNum == 41)
+ playSound(makeRid(1, 0x8F6), true);
+
+}
+
+void GnapEngine::endSceneInit() {
+ showCursor();
+ if (_newGrabCursorSpriteIndex >= 0)
+ setGrabCursorSprite(_newGrabCursorSpriteIndex);
+}
+
+void GnapEngine::afterScene() {
+ if (_gameDone)
+ return;
+
+ if (_newCursorValue == _cursorValue && _newSceneNum != 0 && _newSceneNum != 16 &&
+ _newSceneNum != 47 && _newSceneNum != 48 && _newSceneNum != 54 && _newSceneNum != 49 &&
+ _newSceneNum != 50 && _newSceneNum != 51 && _newSceneNum != 52)
+ _newGrabCursorSpriteIndex = _grabCursorSpriteIndex;
+ else
+ _newGrabCursorSpriteIndex = -1;
+
+ setGrabCursorSprite(-1);
+
+ _gameSys->requestClear2(false);
+ _gameSys->requestClear1();
+ _gameSys->waitForUpdate();
+
+ _gameSys->requestClear2(false);
+ _gameSys->requestClear1();
+ _gameSys->waitForUpdate();
+
+ screenEffect(0, 0, 0, 0);
+
+ _dat->close(0);
+
+ for (int animationIndex = 0; animationIndex < 12; ++animationIndex)
+ _gameSys->setAnimation(0, 0, animationIndex);
+
+ clearKeyStatus1(Common::KEYCODE_p);
+
+ _mouseClickState._left = false;
+ _mouseClickState._right = false;
+
+}
+
+void GnapEngine::checkGameKeys() {
+ if (isKeyStatus1(Common::KEYCODE_p)) {
+ clearKeyStatus1(Common::KEYCODE_p);
+ pauseGame();
+ updatePause();
+ }
+}
+
+void GnapEngine::startSoundTimerA(int timerIndex) {
+ _soundTimerIndexA = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 100;
+}
+
+int GnapEngine::playSoundA() {
+ static const int kSoundIdsA[] = {
+ 0x93E, 0x93F, 0x941, 0x942, 0x943, 0x944,
+ 0x945, 0x946, 0x947, 0x948, 0x949
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexA]) {
+ _timers[_soundTimerIndexA] = getRandom(50) + 100;
+ soundId = kSoundIdsA[getRandom(11)];
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startSoundTimerB(int timerIndex) {
+ _soundTimerIndexB = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 150;
+}
+
+int GnapEngine::playSoundB() {
+ static const int kSoundIdsB[] = {
+ 0x93D, 0x929, 0x92A, 0x92B, 0x92C, 0x92D,
+ 0x92E, 0x92F, 0x930, 0x931, 0x932, 0x933,
+ 0x934, 0x935, 0x936, 0x937, 0x938, 0x939,
+ 0x93A
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexB]) {
+ _timers[_soundTimerIndexB] = getRandom(50) + 150;
+ soundId = kSoundIdsB[getRandom(19)];
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startSoundTimerC(int timerIndex) {
+ _soundTimerIndexC = timerIndex;
+ _timers[timerIndex] = getRandom(50) + 150;
+}
+
+int GnapEngine::playSoundC() {
+ static const int kSoundIdsC[] = {
+ 0x918, 0x91F, 0x920, 0x922, 0x923, 0x924,
+ 0x926
+ };
+
+ int soundId = -1;
+
+ if (!_timers[_soundTimerIndexC]) {
+ _timers[_soundTimerIndexC] = getRandom(50) + 150;
+ soundId = kSoundIdsC[getRandom(7)] ;
+ playSound(soundId | 0x10000, false);
+ }
+ return soundId;
+}
+
+void GnapEngine::startIdleTimer(int timerIndex) {
+ _idleTimerIndex = timerIndex;
+ _timers[timerIndex] = 3000;
+}
+
+void GnapEngine::updateIdleTimer() {
+ if (!_timers[_idleTimerIndex]) {
+ _timers[_idleTimerIndex] = 3000;
+ _gameSys->insertSequence(0x1088B, 255, 0, 0, kSeqNone, 0, 0, 75);
+ }
+}
+
+void GnapEngine::screenEffect(int dir, byte r, byte g, byte b) {
+ int startVal = 0;
+ if (dir == 1)
+ startVal = 300;
+
+ for (int y = startVal; y < startVal + 300 && !_gameDone; y += 50) {
+ _gameSys->fillSurface(nullptr, 0, y, 800, 50, r, g, b);
+ _gameSys->fillSurface(nullptr, 0, 549 - y + 1, 800, 50, r, g, b);
+ gameUpdateTick();
+ _system->delayMillis(50);
+ }
+}
+
+bool GnapEngine::isKeyStatus1(int key) {
+ return _keyPressState[key];
+}
+
+bool GnapEngine::isKeyStatus2(int key) {
+ return _keyDownState[key];
+}
+
+void GnapEngine::clearKeyStatus1(int key) {
+ _keyPressState[key] = false;
+ _keyDownState[key] = false;
+}
+
+void GnapEngine::clearAllKeyStatus1() {
+ memset(_keyPressState, 0, sizeof(_keyPressState));
+ memset(_keyDownState, 0, sizeof(_keyDownState));
+}
+
+void GnapEngine::deleteSurface(Graphics::Surface **surface) {
+ if (surface && *surface) {
+ (*surface)->free();
+ delete *surface;
+ *surface = nullptr;
+ }
+}
+
+bool GnapEngine::testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2) {
+ if (_mouseClickState._left && someStatus == _gnap->_actionStatus) {
+ _isLeavingScene = false;
+ _gameSys->setAnimation(0, 0, animationIndex);
+ _gnap->_actionStatus = -1;
+ _plat->_actionStatus = -1;
+ _gnap->walkTo(Common::Point(gridX1, gridY1), -1, -1, 1);
+ _plat->walkTo(Common::Point(gridX2, gridY2), -1, -1, 1);
+ _mouseClickState._left = false;
+ return true;
+ }
+ return false;
+}
+
+void GnapEngine::doCallback(int callback) {
+ switch (callback) {
+ case 8:
+ case 10:
+ case 20:
+ _scene->updateAnimationsCb();
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GnapEngine::initGlobalSceneVars() {
+ // Shared by scenes 17 && 18
+ _s18GarbageCanPos = 8;
+
+ // Toy UFO
+ _toyUfoId = 0;
+ _toyUfoActionStatus = -1;
+ _toyUfoX = 0;
+ _toyUfoY = 50;
+}
+
+void GnapEngine::playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3) {
+ setGrabCursorSprite(-1);
+ _gameSys->setAnimation(sequenceId2, _gnap->_id, 0);
+ _gameSys->insertSequence(sequenceId2, _gnap->_id,
+ makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id,
+ kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8));
+ _gnap->_sequenceId = sequenceId2;
+ _gnap->_sequenceDatNum = 0;
+ while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone)
+ gameUpdateTick();
+ hideCursor();
+ addFullScreenSprite(fullScreenSpriteId, 255);
+ _gameSys->setAnimation(sequenceId1, 256, 0);
+ _gameSys->insertSequence(sequenceId1, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone)
+ gameUpdateTick();
+ _gameSys->setAnimation(sequenceId3, _gnap->_id, 0);
+ _gameSys->insertSequence(sequenceId3, _gnap->_id,
+ makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id,
+ kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8));
+ removeFullScreenSprite();
+ showCursor();
+ _gnap->_sequenceId = sequenceId3;
+}
+
+void GnapEngine::toyUfoSetStatus(int flagNum) {
+ clearFlag(kGFUnk16);
+ clearFlag(kGFJointTaken);
+ clearFlag(kGFUnk18);
+ clearFlag(kGFGroceryStoreHatTaken);
+ setFlag(flagNum);
+}
+
+int GnapEngine::toyUfoGetSequenceId() {
+ if (isFlag(kGFUnk16))
+ return 0x84E;
+ if (isFlag(kGFJointTaken))
+ return 0x84B;
+ if (isFlag(kGFUnk18))
+ return 0x84D;
+ if (isFlag(kGFGroceryStoreHatTaken))
+ return 0x84C;
+ return 0x84E;
+}
+
+bool GnapEngine::toyUfoCheckTimer() {
+ if (!isFlag(kGFGnapControlsToyUFO) || isFlag(kGFUnk18) || _timers[9] ||
+ _toyUfoSequenceId == 0x870 || _toyUfoSequenceId == 0x871 || _toyUfoSequenceId == 0x872 || _toyUfoSequenceId == 0x873)
+ return false;
+ _sceneDone = true;
+ _newSceneNum = 41;
+ return true;
+}
+
+void GnapEngine::toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex) {
+ GridStruct flyNodes[34];
+
+ if (destX == -1)
+ destX = _leftClickMouseX;
+
+ if (destY == -1)
+ destY = _leftClickMouseY;
+
+ int clippedDestX = CLIP(destX, minX, maxX);
+ int clippedDestY = CLIP(destY, minY, maxY);
+ int dirX = 0, dirY = 0; // 0, -1 or 1
+
+ if (clippedDestX != _toyUfoX)
+ dirX = (clippedDestX - _toyUfoX) / ABS(clippedDestX - _toyUfoX);
+
+ if (clippedDestY != _toyUfoY)
+ dirY = (clippedDestY - _toyUfoY) / ABS(clippedDestY - _toyUfoY);
+
+ int deltaX = ABS(clippedDestX - _toyUfoX);
+ int deltaY = ABS(clippedDestY - _toyUfoY);
+
+ int i = 0;
+ if (deltaY > deltaX) {
+ int flyDirYIncr = 32;
+ int gridDistY = deltaY / flyDirYIncr;
+ int curMove = 0;
+ while (curMove < deltaY && i < 34) {
+ if (gridDistY - 5 >= i) {
+ flyDirYIncr = MIN(36, 8 * i + 8);
+ } else {
+ flyDirYIncr = MAX(6, flyDirYIncr - 3);
+ }
+ curMove += flyDirYIncr;
+ flyNodes[i]._gridX1 = _toyUfoX + dirX * deltaX * curMove / deltaY;
+ flyNodes[i]._gridY1 = _toyUfoY + dirY * curMove;
+ ++i;
+ }
+ } else {
+ int flyDirXIncr = 36;
+ int gridDistX = deltaX / flyDirXIncr;
+ int curMove = 0;
+ while (curMove < deltaX && i < 34) {
+ if (gridDistX - 5 >= i) {
+ flyDirXIncr = MIN(38, 8 * i + 8);
+ } else {
+ flyDirXIncr = MAX(6, flyDirXIncr - 3);
+ }
+ curMove += flyDirXIncr;
+ flyNodes[i]._gridX1 = _toyUfoX + dirX * curMove;
+ flyNodes[i]._gridY1 = _toyUfoY + dirY * deltaY * curMove / deltaX;
+ ++i;
+ }
+ }
+
+ int nodesCount = i - 1;
+
+ _toyUfoX = clippedDestX;
+ _toyUfoY = clippedDestY;
+
+ if (nodesCount > 0) {
+ int seqId = 0;
+ if (isFlag(kGFUnk16))
+ seqId = 0x867;
+ else if (isFlag(kGFJointTaken))
+ seqId = 0x84F;
+ else if (isFlag(kGFUnk18))
+ seqId = 0x85F;
+ else if (isFlag(kGFGroceryStoreHatTaken))
+ seqId = 0x857;
+ else
+ error("Unhandled flag in GnapEngine::toyUfoFlyTo(): 0x%x", _gameFlags);
+ flyNodes[0]._sequenceId = seqId;
+ flyNodes[0]._id = 0;
+ _gameSys->insertSequence(seqId | 0x10000, 0,
+ _toyUfoSequenceId | 0x10000, _toyUfoId,
+ kSeqSyncWait, 0, flyNodes[0]._gridX1 - 365, flyNodes[0]._gridY1 - 128);
+ for (i = 1; i < nodesCount; ++i) {
+ flyNodes[i]._sequenceId = seqId + (i % 8);
+ flyNodes[i]._id = i;
+ _gameSys->insertSequence(flyNodes[i]._sequenceId | 0x10000, flyNodes[i]._id,
+ flyNodes[i - 1]._sequenceId | 0x10000, flyNodes[i - 1]._id,
+ kSeqSyncWait, 0,
+ flyNodes[i]._gridX1 - 365, flyNodes[i]._gridY1 - 128);
+ }
+
+ _toyUfoSequenceId = flyNodes[nodesCount - 1]._sequenceId;
+ _toyUfoId = flyNodes[nodesCount - 1]._id;
+
+ if (animationIndex >= 0)
+ _gameSys->setAnimation(_toyUfoSequenceId | 0x10000, _toyUfoId, animationIndex);
+
+ }
+}
+
+void GnapEngine::playMidi(const char *name) {
+ if (_music)
+ return;
+
+ _music = new MusicPlayer(name);
+ _music->playSMF(true);
+}
+
+void GnapEngine::stopMidi() {
+ if (_music) {
+ _music->stop();
+ delete _music;
+ _music = nullptr;
+ }
+}
+} // End of namespace Gnap
diff --git a/engines/gnap/gnap.h b/engines/gnap/gnap.h
new file mode 100644
index 0000000000..dbefa31795
--- /dev/null
+++ b/engines/gnap/gnap.h
@@ -0,0 +1,475 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GNAP_H
+#define GNAP_GNAP_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/random.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/system.h"
+#include "common/winexe.h"
+#include "common/winexe_pe.h"
+#include "engines/engine.h"
+#include "graphics/pixelformat.h"
+#include "graphics/wincursor.h"
+#include "graphics/fontman.h"
+#include "graphics/font.h"
+#include "graphics/fonts/ttf.h"
+
+#include "gnap/debugger.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/scenecore.h"
+#include "gnap/character.h"
+#include "gnap/music.h"
+
+struct ADGameDescription;
+
+namespace Gnap {
+
+class DatManager;
+class SequenceResource;
+class SpriteResource;
+class GameSys;
+class SoundMan;
+class MusicPlayer;
+
+#define GNAP_SAVEGAME_VERSION 2
+
+struct MouseButtonState {
+ bool _left;
+ bool _right;
+ MouseButtonState() : _left(false), _right(false) {
+ }
+};
+
+struct Hotspot {
+ Common::Rect _rect;
+ uint16 _flags;
+
+ bool isPointInside(Common::Point pos) const {
+ return _rect.contains(pos);
+ }
+
+ bool isFlag(uint16 flag) const {
+ return (_flags & flag) != 0;
+ }
+
+ void clearRect() {
+ _rect = Common::Rect(0, 0, 0, 0);
+ }
+};
+
+const int kMaxTimers = 10;
+
+enum GnapDebugChannels {
+ kDebugBasic = 1 << 0,
+ kDebugMusic = 1 << 1
+};
+
+enum {
+ SF_NONE = 0x0000,
+ SF_LOOK_CURSOR = 0x0001,
+ SF_GRAB_CURSOR = 0x0002,
+ SF_TALK_CURSOR = 0x0004,
+ SF_PLAT_CURSOR = 0x0008,
+ SF_DISABLED = 0x0010,
+ SF_WALKABLE = 0x0020,
+ SF_EXIT_L_CURSOR = 0x0040,
+ SF_EXIT_R_CURSOR = 0x0080,
+ SF_EXIT_U_CURSOR = 0x0100,
+ SF_EXIT_D_CURSOR = 0x0200,
+ SF_EXIT_NW_CURSOR = 0x0400,
+ SF_EXIT_NE_CURSOR = 0x0800,
+ SF_EXIT_SW_CURSOR = 0x1000,
+ SF_EXIT_SE_CURSOR = 0x2000
+};
+
+enum {
+ LOOK_CURSOR = 0,
+ GRAB_CURSOR = 1,
+ TALK_CURSOR = 2,
+ PLAT_CURSOR = 3,
+ NOLOOK_CURSOR = 4,
+ NOGRAB_CURSOR = 5,
+ NOTALK_CURSOR = 6,
+ NOPLAT_CURSOR = 7,
+ EXIT_L_CURSOR = 8,
+ EXIT_R_CURSOR = 9,
+ EXIT_U_CURSOR = 10,
+ EXIT_D_CURSOR = 11,
+ EXIT_NE_CURSOR = 12,
+ EXIT_NW_CURSOR = 13,
+ EXIT_SE_CURSOR = 14,
+ EXIT_SW_CURSOR = 15,
+ WAIT_CURSOR = 16
+};
+
+enum {
+ kGSPullOutDevice = 0,
+ kGSPullOutDeviceNonWorking = 1,
+ kGSIdle = 2,
+ kGSBrainPulsating = 3,
+ kGSImpossible = 4,
+ kGSScratchingHead = 5,
+ kGSDeflect = 6,
+ kGSUseDevice = 7,
+ kGSMoan1 = 8,
+ kGSMoan2 = 9
+};
+
+enum {
+ kItemMagazine = 0,
+ kItemMud = 1,
+ kItemGrass = 2,
+ kItemDisguise = 3,
+ kItemNeedle = 4,
+ kItemTwig = 5,
+ kItemGas = 6,
+ kItemKeys = 7,
+ kItemDice = 8,
+ kItemTongs = 9,
+ kItemQuarter = 10,
+ kItemQuarterWithHole = 11,
+ kItemDiceQuarterHole = 12,
+ kItemWrench = 13,
+ kItemCowboyHat = 14,
+ kItemGroceryStoreHat = 15,
+ kItemBanana = 16,
+ kItemTickets = 17,
+ kItemPicture = 18,
+ kItemEmptyBucket = 19,
+ kItemBucketWithBeer = 20,
+ kItemBucketWithPill = 21,
+ kItemPill = 22,
+ kItemHorn = 23,
+ kItemJoint = 24,
+ kItemChickenBucket = 25,
+ kItemGum = 26,
+ kItemSpring = 27,
+ kItemLightbulb = 28,
+ kItemCereals = 29
+};
+
+enum {
+ kGFPlatypus = 0,
+ kGFMudTaken = 1,
+ kGFNeedleTaken = 2,
+ kGFTwigTaken = 3,
+ kGFUnk04 = 4,
+ kGFKeysTaken = 5,
+ kGFGrassTaken = 6,
+ kGFBarnPadlockOpen = 7,
+ kGFTruckFilledWithGas = 8,
+ kGFTruckKeysUsed = 9,
+ kGFPlatypusDisguised = 10,
+ kGFSceneFlag1 = 11,
+ kGFGnapControlsToyUFO = 12,
+ kGFUnk13 = 13, // Tongue Fight Won?
+ kGFUnk14 = 14,
+ kGFSpringTaken = 15,
+ kGFUnk16 = 16,
+ kGFJointTaken = 17,
+ kGFUnk18 = 18,
+ kGFGroceryStoreHatTaken = 19,
+ kGFPictureTaken = 20,
+ kGFUnk21 = 21,
+ kGFUnk22 = 22,
+ kGFUnk23 = 23,
+ kGFUnk24 = 24,
+ kGFUnk25 = 25,
+ kGFPlatypusTalkingToAssistant = 26,
+ kGFUnk27 = 27,
+ kGFUnk28 = 28,
+ kGFGasTaken = 29,
+ kGFUnk30 = 30,
+ kGFUnk31 = 31
+};
+
+struct GnapSavegameHeader {
+ uint8 _version;
+ Common::String _saveName;
+ Graphics::Surface *_thumbnail;
+ int _year, _month, _day;
+ int _hour, _minute;
+};
+
+class GnapEngine : public Engine {
+protected:
+ Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+public:
+ GnapEngine(OSystem *syst, const ADGameDescription *gd);
+ ~GnapEngine();
+private:
+ const ADGameDescription *_gameDescription;
+ Graphics::PixelFormat _pixelFormat;
+ int _loadGameSlot;
+
+public:
+ Common::RandomSource *_random;
+ Common::PEResources *_exe;
+
+ DatManager *_dat;
+ SpriteCache *_spriteCache;
+ SoundCache *_soundCache;
+ SequenceCache *_sequenceCache;
+ GameSys *_gameSys;
+ SoundMan *_soundMan;
+ Debugger *_debugger;
+ Scene *_scene;
+ PlayerGnap *_gnap;
+ PlayerPlat *_plat;
+ MusicPlayer *_music;
+ Graphics::Font *_font;
+
+ Common::MemoryWriteStreamDynamic *_tempThumbnail;
+
+ int _lastUpdateClock;
+ bool _gameDone;
+
+ bool _keyPressState[512];
+ bool _keyDownState[512];
+
+ bool _isPaused;
+ Graphics::Surface *_pauseSprite;
+ int _timers[kMaxTimers], _savedTimers[kMaxTimers];
+
+ MouseButtonState _mouseButtonState;
+ MouseButtonState _mouseClickState;
+
+ bool _sceneSavegameLoaded, _wasSavegameLoaded;
+
+ Graphics::Surface *_backgroundSurface;
+ int _prevSceneNum, _currentSceneNum, _newSceneNum;
+ bool _sceneDone, _sceneWaiting;
+
+ uint32 _inventory, _gameFlags;
+
+ Hotspot _hotspots[20];
+ Common::Point _hotspotsWalkPos[20];
+ int _hotspotsCount;
+ int _sceneClickedHotspot;
+
+ bool _isWaiting;
+ bool _isLeavingScene;
+
+ bool _isStockDatLoaded;
+
+ int _newCursorValue, _cursorValue;
+
+ int _verbCursor, _cursorIndex;
+ Common::Point _mousePos;
+ int _leftClickMouseX, _leftClickMouseY;
+
+ Graphics::Surface *_grabCursorSprite;
+ int _currGrabCursorX, _currGrabCursorY;
+ int _grabCursorSpriteIndex, _newGrabCursorSpriteIndex;
+
+ Graphics::Surface *_fullScreenSprite;
+ int _fullScreenSpriteId;
+
+ int _deviceX1, _deviceY1;
+
+ int _soundTimerIndexA;
+ int _soundTimerIndexB;
+ int _soundTimerIndexC;
+ int _idleTimerIndex;
+
+ void updateEvents();
+ void gameUpdateTick();
+ void saveTimers();
+ void restoreTimers();
+
+ void pauseGame();
+ void resumeGame();
+ void updatePause();
+
+ int getRandom(int max);
+
+ int readSavegameDescription(int savegameNum, Common::String &description);
+ int loadSavegame(int savegameNum);
+ Common::Error saveGameState(int slot, const Common::String &desc);
+ Common::Error loadGameState(int slot);
+ Common::String generateSaveName(int slot);
+ void synchronize(Common::Serializer &s);
+ void writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header);
+ static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header);
+
+ void delayTicks(int val, int idx, bool updateCursor);
+ void delayTicksA(int val, int idx);
+ void delayTicksCursor(int val);
+
+ void setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags = SF_NONE,
+ int16 walkX = -1, int16 walkY = -1);
+ int getHotspotIndexAtPos(Common::Point pos);
+ void updateCursorByHotspot();
+ int getClickedHotspotId();
+
+ int getInventoryItemSpriteNum(int index);
+
+ void updateMouseCursor();
+ void setVerbCursor(int verbCursor);
+ void setCursor(int cursorIndex);
+ void showCursor();
+ void hideCursor();
+
+ void setGrabCursorSprite(int index);
+ void createGrabCursorSprite(int spriteId);
+ void freeGrabCursorSprite();
+ void updateGrabCursorSprite(int x, int y);
+
+ void invClear();
+ void invAdd(int itemId);
+ void invRemove(int itemId);
+ bool invHas(int itemId);
+
+ void clearFlags();
+ void setFlag(int num);
+ void clearFlag(int num);
+ bool isFlag(int num);
+
+ Graphics::Surface *addFullScreenSprite(int resourceId, int id);
+ void removeFullScreenSprite();
+ void showFullScreenSprite(int resourceId);
+
+ void queueInsertDeviceIcon();
+ void insertDeviceIconActive();
+ void removeDeviceIconActive();
+ void setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2);
+
+ int getSequenceTotalDuration(int resourceId);
+
+ bool isSoundPlaying(int resourceId);
+ void playSound(int resourceId, bool looping);
+ void stopSound(int resourceId);
+ void setSoundVolume(int resourceId, int volume);
+
+ void updateTimers();
+
+ void initGameFlags(int num);
+ void loadStockDat();
+
+ void mainLoop();
+ void initScene();
+ void endSceneInit();
+ void afterScene();
+
+ int initSceneLogic();
+ void runSceneLogic();
+
+ void checkGameKeys();
+
+ void startSoundTimerA(int timerIndex);
+ int playSoundA();
+ void startSoundTimerB(int timerIndex);
+ int playSoundB();
+ void startSoundTimerC(int timerIndex);
+ int playSoundC();
+ void startIdleTimer(int timerIndex);
+ void updateIdleTimer();
+
+ void screenEffect(int dir, byte r, byte g, byte b);
+
+ bool isKeyStatus1(int key);
+ bool isKeyStatus2(int key);
+ void clearKeyStatus1(int key);
+ void clearAllKeyStatus1();
+
+ void deleteSurface(Graphics::Surface **surface);
+
+ // Menu
+ int _menuStatus;
+ int _menuSpritesIndex;
+ bool _menuDone;
+ Graphics::Surface *_menuBackgroundSurface;
+ Graphics::Surface *_menuQuitQuerySprite;
+ Graphics::Surface *_largeSprite;
+ Graphics::Surface *_menuSaveLoadSprite;
+ Graphics::Surface *_menuSprite2;
+ Graphics::Surface *_menuSprite1;
+ char _savegameFilenames[7][30];
+ Graphics::Surface *_savegameSprites[7];
+ Graphics::Surface *_spriteHandle;
+ Graphics::Surface *_cursorSprite;
+ int _menuInventoryIndices[30];
+ Graphics::Surface *_menuInventorySprites[30];
+ int _savegameIndex;
+ void createMenuSprite();
+ void freeMenuSprite();
+ void initMenuHotspots1();
+ void initMenuHotspots2();
+ void initMenuQuitQueryHotspots();
+ void initSaveLoadHotspots();
+ void drawInventoryFrames();
+ void insertInventorySprites();
+ void removeInventorySprites();
+ void runMenu();
+ void updateMenuStatusInventory();
+ void updateMenuStatusMainMenu();
+ void updateMenuStatusSaveGame();
+ void updateMenuStatusLoadGame();
+ void updateMenuStatusQueryQuit();
+
+ // Grid common
+ int _gridMinX, _gridMinY;
+ int _gridMaxX, _gridMaxY;
+ bool isPointBlocked(int gridX, int gridY);
+ bool isPointBlocked(Common::Point gridPos);
+ void initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY);
+ bool testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2);
+
+ // Gnap
+ void doCallback(int callback);
+
+ // Scenes
+ int _toyUfoNextSequenceId, _toyUfoSequenceId;
+ int _toyUfoId;
+ int _toyUfoActionStatus;
+ int _toyUfoX;
+ int _toyUfoY;
+
+ void initGlobalSceneVars();
+ void playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3);
+
+ // Shared by scenes 17 & 18
+ int _s18GarbageCanPos;
+
+ // Scene 4x
+ void toyUfoSetStatus(int flagNum);
+ int toyUfoGetSequenceId();
+ bool toyUfoCheckTimer();
+ void toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex);
+
+ void playMidi(const char *name);
+ void stopMidi();
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GNAP_H
diff --git a/engines/gnap/grid.cpp b/engines/gnap/grid.cpp
new file mode 100644
index 0000000000..aa6da71395
--- /dev/null
+++ b/engines/gnap/grid.cpp
@@ -0,0 +1,995 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+void GnapEngine::initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY) {
+ _gridMinX = gridMinX;
+ _gridMinY = gridMinY;
+ _gridMaxX = gridMaxX;
+ _gridMaxY = gridMaxY;
+ _gnap->_gridX = 410 - gridMinX;
+ _gnap->_gridY = 450 - gridMinY;
+ _plat->_gridX = 396 - gridMinX;
+ _plat->_gridY = 347 - gridMinY;
+}
+
+bool GnapEngine::isPointBlocked(Common::Point gridPos) {
+ return isPointBlocked(gridPos.x, gridPos.y);
+}
+
+bool GnapEngine::isPointBlocked(int gridX, int gridY) {
+
+ if (gridX < 0 || gridX >= _gridMaxX || gridY < 0 || gridY >= _gridMaxY)
+ return true;
+
+ if ((_gnap->_pos == Common::Point(gridX, gridY)) || (_plat->_pos == Common::Point(gridX, gridY)))
+ return true;
+
+ Common::Point pos = Common::Point(_gridMinX + 75 * gridX, _gridMinY + 48 * gridY);
+
+ for (int i = 0; i < _hotspotsCount; ++i) {
+ if (_hotspots[i].isPointInside(pos) && !(_hotspots[i]._flags & SF_WALKABLE))
+ return true;
+ }
+
+ return false;
+}
+
+/******************************************************************************/
+
+int PlayerGnap::getWalkStopSequenceId(int deltaX, int deltaY) {
+ static const int gnapWalkStopSequenceIds[9] = {
+ 0x7BC, 0x7BA, 0x7BA,
+ 0x7BC, 0x000, 0x7BA,
+ 0x7BB, 0x7B9, 0x7B9
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert (id >= 0 && id < 9 );
+ return gnapWalkStopSequenceIds[id];
+}
+
+Facing PlayerGnap::getWalkFacing(int deltaX, int deltaY) {
+ static const Facing gnapWalkFacings[9] = {
+ kDirUpLeft, kDirBottomLeft, kDirBottomLeft,
+ kDirUpLeft, kDirIdleLeft, kDirBottomLeft,
+ kDirUpRight, kDirBottomRight, kDirBottomRight
+ };
+
+ int id = 3 * (deltaX + 1) + deltaY + 1;
+ assert (id >= 0 && id < 9 );
+ return gnapWalkFacings[id];
+}
+
+bool PlayerGnap::findPath1(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerGnap::findPath2(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerGnap::findPath3(int gridX, int gridY) {
+ int gridIncr = 1;
+ bool done = false;
+
+ while (!done && gridIncr < _vm->_gridMaxX) {
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath1(gridX + gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath1(gridX - gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath1(gridX, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath1(gridX, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath1(gridX + gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath1(gridX - gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath1(gridX + gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath1(gridX - gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath2(gridX + gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath2(gridX - gridIncr, gridY, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath2(gridX, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath2(gridX, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath2(gridX + gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath2(gridX - gridIncr, gridY + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath2(gridX + gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX + i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath2(gridX - gridIncr, gridY - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = gridX - i;
+ _walkNodes[i]._gridY1 = gridY - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ ++gridIncr;
+ }
+
+ return done;
+}
+
+bool PlayerGnap::findPath4(int gridX, int gridY) {
+ bool result = false;
+
+ _walkNodesCount = 0;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ }
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaY = _walkDirYIncr;
+ }
+ }
+
+ if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) {
+ _walkDestX = gridX + _walkDirX * _walkDirXIncr;
+ _walkDestY = gridY + _walkDirY * _walkDirYIncr;
+ result = false;
+ } else {
+ result = true;
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+bool PlayerPlat::findPath1(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerPlat::findPath2(int gridX, int gridY, int index) {
+ _walkNodesCount = index;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else
+ return false;
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else
+ return false;
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else
+ return false;
+ }
+
+ return true;
+}
+
+bool PlayerPlat::findPath3(int gridX, int gridY) {
+ int gridIncr = 1;
+ bool done = false;
+
+ while (!done && gridIncr < _vm->_gridMaxX) {
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath1(_pos.x + gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath1(_pos.x - gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath1(_pos.x, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath1(_pos.x, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath1(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath1(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath1(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath1(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath2(_pos.x + gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath2(_pos.x - gridIncr, _pos.y, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 0;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath2(_pos.x, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath2(_pos.x, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 0;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath2(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath2(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y + i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = 1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath2(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x + i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = 1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath2(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) {
+ for (int i = 0; i < gridIncr; ++i) {
+ _walkNodes[i]._gridX1 = _pos.x - i;
+ _walkNodes[i]._gridY1 = _pos.y - i;
+ _walkNodes[i]._deltaX = -1;
+ _walkNodes[i]._deltaY = -1;
+ }
+ done = true;
+ break;
+ }
+ ++gridIncr;
+ }
+
+ return done;
+}
+
+bool PlayerPlat::findPath4(int gridX, int gridY) {
+ bool result = false;
+
+ _walkNodesCount = 0;
+ _walkDirXIncr = 0;
+ _walkDirYIncr = 0;
+ _walkDeltaX = ABS(_walkDestX - gridX);
+ _walkDeltaY = ABS(_walkDestY - gridY);
+
+ if (_walkDeltaX)
+ _walkDirX = (_walkDestX - gridX) / _walkDeltaX;
+ else
+ _walkDirX = 0;
+
+ if (_walkDeltaY)
+ _walkDirY = (_walkDestY - gridY) / _walkDeltaY;
+ else
+ _walkDirY = 0;
+
+ while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirXIncr;
+ ++_walkDirYIncr;
+ } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) {
+ if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ } else {
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ _walkDeltaY = _walkDirYIncr;
+ --_walkNodesCount;
+ }
+ }
+ ++_walkNodesCount;
+ }
+
+ while (_walkDirXIncr < _walkDeltaX) {
+ _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr;
+ _walkNodes[_walkNodesCount]._gridY1 = _walkDestY;
+ if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) {
+ _walkNodes[_walkNodesCount]._deltaX = _walkDirX;
+ _walkNodes[_walkNodesCount]._deltaY = 0;
+ ++_walkDirXIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaX = _walkDirXIncr;
+ }
+ }
+
+ while (_walkDirYIncr < _walkDeltaY) {
+ _walkNodes[_walkNodesCount]._gridX1 = _walkDestX;
+ _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr;
+ if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) {
+ _walkNodes[_walkNodesCount]._deltaX = 0;
+ _walkNodes[_walkNodesCount]._deltaY = _walkDirY;
+ ++_walkDirYIncr;
+ ++_walkNodesCount;
+ } else {
+ _walkDeltaY = _walkDirYIncr;
+ }
+ }
+
+ if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) {
+ _walkDestX = gridX + _walkDirX * _walkDirXIncr;
+ _walkDestY = gridY + _walkDirY * _walkDirYIncr;
+ result = false;
+ } else {
+ result = true;
+ }
+
+ return result;
+}
+
+void PlayerPlat::makeRoom() {
+ int rndGridX, rndGridY;
+ do {
+ rndGridY = _vm->getRandom(_vm->_gridMaxY);
+ rndGridX = _vm->getRandom(_vm->_gridMaxX);
+ } while (ABS(rndGridX - _pos.x) > 4 || ABS(rndGridY - _pos.y) > 3 ||
+ _vm->isPointBlocked(rndGridX, rndGridY));
+ walkTo(Common::Point(rndGridX, rndGridY), -1, -1, 1);
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/menu.cpp b/engines/gnap/menu.cpp
new file mode 100644
index 0000000000..2bfe7300df
--- /dev/null
+++ b/engines/gnap/menu.cpp
@@ -0,0 +1,888 @@
+/* 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.
+ *
+ */
+
+#include "common/config-manager.h"
+#include "common/savefile.h"
+#include "common/translation.h"
+
+#include "gui/saveload.h"
+#include "graphics/thumbnail.h"
+
+#include "gnap/gnap.h"
+#include "gnap/datarchive.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+void GnapEngine::createMenuSprite() {
+ _menuBackgroundSurface = _gameSys->createSurface(0x10002);
+}
+
+void GnapEngine::freeMenuSprite() {
+ _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260);
+ delayTicksCursor(5);
+ deleteSurface(&_menuBackgroundSurface);
+}
+
+void GnapEngine::initMenuHotspots1() {
+ int curId = 0;
+
+ for (int i = 0; i < 3; ++i) {
+ int top = 74 * i + 69;
+ for (int j = 0; j < 3; ++j) {
+ int left = 87 * j + 262;
+ _hotspots[curId]._rect = Common::Rect(left, top, left + 79, top + 66);
+ _hotspots[curId]._flags = SF_NONE;
+ ++curId;
+ }
+ }
+
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::initMenuHotspots2() {
+ int curId = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ int top = 48 * i + 85;
+ _hotspots[curId]._rect = Common::Rect(312, top, 465, top + 37);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ _hotspots[curId]._rect = Common::Rect(500, 72, 527, 99);
+ _hotspots[curId]._flags = SF_DISABLED;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::initMenuQuitQueryHotspots() {
+ _hotspots[0]._rect = Common::Rect(311, 197, 377, 237);
+ _hotspots[0]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[1]._rect = Common::Rect(403, 197, 469, 237);
+ _hotspots[1]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[2]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[2]._flags = SF_GRAB_CURSOR;
+
+ _hotspots[3]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[3]._flags = SF_NONE;
+
+ _hotspots[4]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[4]._flags = SF_NONE;
+
+ _hotspotsCount = 5;
+}
+
+void GnapEngine::initSaveLoadHotspots() {
+ int curId = 0;
+
+ for (int i = 0; i < 7; ++i ) {
+ int top = 31 * i + 74;
+ _hotspots[curId]._rect = Common::Rect(288, top, 379, top + 22);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ if (_menuStatus == 2) {
+ _hotspots[curId]._rect = Common::Rect(416, 160, 499, 188);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+ ++curId;
+ }
+
+ _hotspots[curId]._rect = Common::Rect(416, 213, 499, 241);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460);
+ _hotspots[curId]._flags = SF_GRAB_CURSOR;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580);
+ _hotspots[curId]._flags = SF_NONE;
+
+ ++curId;
+ _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599);
+ _hotspots[curId]._flags = SF_NONE;
+
+ _hotspotsCount = curId + 1;
+}
+
+void GnapEngine::drawInventoryFrames() {
+ for (int i = 0; i < 9; ++i)
+ _gameSys->drawSpriteToSurface(_menuBackgroundSurface, _hotspots[i]._rect.left - 93, _hotspots[i]._rect.top, 0x10001);
+}
+
+void GnapEngine::insertInventorySprites() {
+ for (int i = 0; i < 9; ++i) {
+ _menuInventoryIndices[i] = -1;
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261);
+ _menuInventorySprites[i] = 0;
+ }
+
+ _menuSpritesIndex = 0;
+
+ for (int index = 0; index < 30 && _menuSpritesIndex < 9; ++index) {
+ if (invHas(index)) {
+ _gameSys->drawSpriteToSurface(_menuBackgroundSurface,
+ _hotspots[_menuSpritesIndex]._rect.left - 93, _hotspots[_menuSpritesIndex]._rect.top, 0x10000);
+ _menuInventorySprites[_menuSpritesIndex] = _gameSys->createSurface(getInventoryItemSpriteNum(index) | 0x10000);
+ if (index != _grabCursorSpriteIndex) {
+ _menuInventoryIndices[_menuSpritesIndex] = index;
+ _gameSys->insertSpriteDrawItem(_menuInventorySprites[_menuSpritesIndex],
+ _hotspots[_menuSpritesIndex]._rect.left + ((79 - _menuInventorySprites[_menuSpritesIndex]->w) / 2),
+ _hotspots[_menuSpritesIndex]._rect.top + ((66 - _menuInventorySprites[_menuSpritesIndex]->h) / 2),
+ 261);
+ }
+ _hotspots[_menuSpritesIndex]._flags = SF_GRAB_CURSOR;
+ ++_menuSpritesIndex;
+ }
+ }
+}
+
+void GnapEngine::removeInventorySprites() {
+ for (int i = 0; i < _menuSpritesIndex; ++i)
+ if (_menuInventorySprites[i])
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[i], 261);
+ delayTicksCursor(5);
+ for (int j = 0; j < _menuSpritesIndex; ++j) {
+ if (_menuInventorySprites[j]) {
+ deleteSurface(&_menuInventorySprites[j]);
+ _menuInventorySprites[j] = 0;
+ _menuInventoryIndices[j] = -1;
+ }
+ }
+ _menuSpritesIndex = 0;
+}
+
+void GnapEngine::runMenu() {
+ _spriteHandle = nullptr;
+ _cursorSprite = nullptr;
+ _menuSprite1 = nullptr;
+ _menuSprite2 = nullptr;
+ _menuSaveLoadSprite = nullptr;
+ _menuQuitQuerySprite = nullptr;
+
+ _menuStatus = 0;
+ _menuDone = false;
+
+ delete _tempThumbnail;
+ _tempThumbnail = new Common::MemoryWriteStreamDynamic;
+ Graphics::saveThumbnail(*_tempThumbnail);
+
+ createMenuSprite();
+ insertDeviceIconActive();
+
+ for (int i = 0; i < 7; ++i) {
+ _savegameFilenames[i][0] = 0;
+ _savegameSprites[i] = nullptr;
+ }
+
+ if (_menuStatus == 0) {
+ invAdd(kItemMagazine);
+ setGrabCursorSprite(-1);
+ hideCursor();
+ initMenuHotspots1();
+ drawInventoryFrames();
+ insertInventorySprites();
+ _gameSys->insertSpriteDrawItem(_menuBackgroundSurface, 93, 0, 260);
+ showCursor();
+ // SetCursorPos(400, 300);
+ setVerbCursor(GRAB_CURSOR);
+ // pollMessages();
+ }
+
+ _timers[2] = 10;
+
+ while (!isKeyStatus1(Common::KEYCODE_BACKSPACE) && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !_sceneDone && !_menuDone) {
+ updateCursorByHotspot();
+
+ switch (_menuStatus) {
+ case 0:
+ updateMenuStatusInventory();
+ break;
+ case 1:
+ updateMenuStatusMainMenu();
+ break;
+ case 2:
+ updateMenuStatusSaveGame();
+ break;
+ case 3:
+ updateMenuStatusLoadGame();
+ break;
+ case 4:
+ updateMenuStatusQueryQuit();
+ break;
+ }
+
+ gameUpdateTick();
+ }
+
+ removeInventorySprites();
+ if (_spriteHandle)
+ _gameSys->removeSpriteDrawItem(_spriteHandle, 261);
+ if (_menuSprite1)
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ if (_menuSprite2)
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ for (int i = 0; i < 7; ++i)
+ if (_savegameSprites[i])
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ if (_cursorSprite)
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ if (_menuSaveLoadSprite)
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ if (_menuQuitQuerySprite)
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ if (_menuBackgroundSurface)
+ _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260);
+
+ delayTicksCursor(5);
+
+ deleteSurface(&_spriteHandle);
+ deleteSurface(&_menuSprite1);
+ deleteSurface(&_menuSprite2);
+ for (int i = 0; i < 7; ++i)
+ deleteSurface(&_savegameSprites[i]);
+ deleteSurface(&_cursorSprite);
+ deleteSurface(&_menuSaveLoadSprite);
+ deleteSurface(&_menuQuitQuerySprite);
+
+ _sceneClickedHotspot = -1;
+
+ _timers[2] = getRandom(20) + 30;
+ _timers[3] = getRandom(200) + 50;
+ _timers[0] = getRandom(75) + 75;
+ _timers[1] = getRandom(20) + 30;
+
+ clearAllKeyStatus1();
+
+ _mouseClickState._left = false;
+
+ removeDeviceIconActive();
+
+ freeMenuSprite();//??? CHECKME
+}
+
+void GnapEngine::updateMenuStatusInventory() {
+ static const struct {
+ int item1, item2, resultItem;
+ } kCombineItems[] = {
+ {kItemGrass, kItemMud, kItemDisguise},
+ {kItemDice, kItemQuarterWithHole, kItemDiceQuarterHole},
+ {kItemPill, kItemBucketWithBeer, kItemBucketWithPill}
+ };
+
+ updateGrabCursorSprite(0, 0);
+ _hotspots[0]._rect = Common::Rect(262, 69, 341, 135);
+ _sceneClickedHotspot = -1;
+ if (_timers[2] == 0)
+ _sceneClickedHotspot = getClickedHotspotId();
+ if (_sceneClickedHotspot == -1 || _sceneClickedHotspot >= _menuSpritesIndex) {
+ if (_sceneClickedHotspot == _hotspotsCount - 3) {
+ if (_grabCursorSpriteIndex == -1) {
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _menuStatus = 1;
+ Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom);
+ drawInventoryFrames();
+ initMenuHotspots2();
+ removeInventorySprites();
+ if (!_menuSprite1)
+ _menuSprite1 = _gameSys->createSurface(0x104F8);
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ _gameSys->insertDirtyRect(dirtyRect);
+ } else {
+ playSound(0x108F5, false);
+ }
+ } else if (_sceneClickedHotspot == _hotspotsCount - 1) {
+ _timers[2] = 10;
+ playSound(0x108F5, false);
+ _menuDone = true;
+ }
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex == -1) {
+ _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261);
+ setGrabCursorSprite(_menuInventoryIndices[_sceneClickedHotspot]);
+ _menuInventoryIndices[_sceneClickedHotspot] = -1;
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] == -1 && _grabCursorSpriteIndex != -1) {
+ _menuInventoryIndices[_sceneClickedHotspot] = _grabCursorSpriteIndex;
+ _gameSys->insertSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot],
+ _hotspots[_sceneClickedHotspot]._rect.left + ((79 - _menuInventorySprites[_sceneClickedHotspot]->w) / 2),
+ _hotspots[_sceneClickedHotspot]._rect.top + (66 - _menuInventorySprites[_sceneClickedHotspot]->h) / 2,
+ 261);
+ setGrabCursorSprite(-1);
+ } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex != -1) {
+ int combineIndex = -1;
+ for (int i = 0; i < ARRAYSIZE(kCombineItems); ++i) {
+ if ((_grabCursorSpriteIndex == kCombineItems[i].item1 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item2) ||
+ (_grabCursorSpriteIndex == kCombineItems[i].item2 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item1)) {
+ combineIndex = i;
+ break;
+ }
+ }
+ if (combineIndex >= 0) {
+ invRemove(kCombineItems[combineIndex].item1);
+ invRemove(kCombineItems[combineIndex].item2);
+ invAdd(kCombineItems[combineIndex].resultItem);
+ playSound(0x108AE, false);
+ deleteSurface(&_spriteHandle); // CHECKME
+ _spriteHandle = _gameSys->createSurface(0x10001);
+ _gameSys->insertSpriteDrawItem(_spriteHandle, _hotspots[_menuSpritesIndex - 1]._rect.left, _hotspots[_menuSpritesIndex - 1]._rect.top, 261);
+ setGrabCursorSprite(kCombineItems[combineIndex].resultItem);
+ removeInventorySprites();
+ insertInventorySprites();
+ delayTicksCursor(5);
+ } else {
+ playSound(0x108F5, false);
+ }
+ }
+}
+
+void GnapEngine::updateMenuStatusMainMenu() {
+ _hotspots[0]._rect = Common::Rect(312, 85, 465, 122);
+ _sceneClickedHotspot = -1;
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ if (_sceneClickedHotspot != 1 && _sceneClickedHotspot != 0) {
+ if (_sceneClickedHotspot != 2 && _hotspotsCount - 1 != _sceneClickedHotspot) {
+ if (_sceneClickedHotspot == 3) {
+ // Quit
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ initMenuQuitQueryHotspots();
+ _menuStatus = 4;
+ if (!_menuQuitQuerySprite)
+ _menuQuitQuerySprite = _gameSys->createSurface(0x104FC);
+ _gameSys->insertSpriteDrawItem(_menuQuitQuerySprite, 254, 93, 262);
+ } else if (_sceneClickedHotspot == 4) {
+ // Pause ?
+ playSound(0x108F4, false);
+ Common::Rect dirtyRect(0, 0, 799, 599);
+ hideCursor();
+ _largeSprite = _gameSys->allocSurface(800, 600);
+
+ for (int i = 0; i < 3; ++i) {
+ _timers[2] = 10;
+
+ if (i == 0) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078D);
+ _gameSys->insertSpriteDrawItem(_largeSprite, 0, 0, 300);
+ playMidi("pause.mid");
+ } else if (i == 1) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078E);
+ _gameSys->insertDirtyRect(dirtyRect);
+ } else if (i == 2) {
+ _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078F);
+ _gameSys->insertDirtyRect(dirtyRect);
+ }
+
+ while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !isKeyStatus1(Common::KEYCODE_RETURN)
+ && !isKeyStatus1(Common::KEYCODE_SPACE) && !_timers[2] && !_gameDone)
+ gameUpdateTick();
+
+ playSound(0x108F5, false);
+ _mouseClickState._left = false;
+ clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ clearKeyStatus1(Common::KEYCODE_RETURN);
+ clearKeyStatus1(Common::KEYCODE_SPACE);
+ }
+
+ _gameSys->removeSpriteDrawItem(_largeSprite, 300);
+ delayTicksCursor(5);
+ deleteSurface(&_largeSprite);
+ showCursor();
+ } else if (_hotspotsCount - 3 == _sceneClickedHotspot) {
+ // Button - Return to the inventory
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ initMenuHotspots1();
+ _menuStatus = 0;
+ if (_menuSprite1)
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ insertInventorySprites();
+ Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom);
+ _gameSys->insertDirtyRect(dirtyRect);
+ }
+ } else {
+ // Resume
+ playSound(0x108F5, false);
+ _menuDone = true;
+ }
+ } else {
+ // Save / Load
+#if 1
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+
+ if (_sceneClickedHotspot == 1) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ Common::String savegameDescription = dialog->getResultString();
+ delete dialog;
+
+ if (savegameId != -1) {
+ saveGameState(savegameId, savegameDescription);
+ }
+ } else {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ int16 savegameId = dialog->runModalWithCurrentTarget();
+ delete dialog;
+
+ if (savegameId != -1) {
+ loadGameState(savegameId);
+ _wasSavegameLoaded = true;
+ _menuDone = true;
+ _sceneDone = true;
+ playSound(0x108F4, false);
+ } else {
+ playSound(0x108F5, false);
+ }
+ }
+ }
+#else
+ // NOTE:
+ // This is the code for the original behavior.
+ // It's currently not working prolery, but could be
+ // fixed to replace the ScummVM screens currently
+ // used.
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite1, 262);
+ if (_menuSaveLoadSprite)
+ deleteSurface(&_menuSaveLoadSprite);
+ if (_sceneClickedHotspot == 1) {
+ // Save
+ _menuStatus = 2;
+ initSaveLoadHotspots();
+ _menuSaveLoadSprite = _gameSys->createSurface(0x104FB);
+ } else {
+ // Load
+ _menuStatus = 3;
+ initSaveLoadHotspots();
+ _menuSaveLoadSprite = _gameSys->createSurface(0x104FA);
+ }
+ _gameSys->insertSpriteDrawItem(_menuSaveLoadSprite, 403, 72, 262);
+ if (!_menuSprite2)
+ _menuSprite2 = _gameSys->createSurface(0x104F9);
+ _gameSys->insertSpriteDrawItem(_menuSprite2, 277, 66, 262);
+ for (int i = 0; i < 7; ++i) {
+ Common::String savegameDescription;
+ if (!_savegameSprites[i])
+ _savegameSprites[i] = _gameSys->allocSurface(111, 40);
+ if (readSavegameDescription(i + 1, savegameDescription) == 0)
+ strncpy(_savegameFilenames[i], savegameDescription.c_str(), 40);
+ _gameSys->drawTextToSurface(_savegameSprites[i], 0, 0, 255, 0, 0, _savegameFilenames[i]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[i], 288, _hotspots[i].top, 263);
+ }
+ _savegameIndex = -1;
+ }
+#endif
+}
+
+Common::Error GnapEngine::saveGameState(int slot, const Common::String &desc) {
+ Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
+ generateSaveName(slot));
+ if (!out)
+ return Common::kCreatingFileFailed;
+
+ GnapSavegameHeader header;
+ header._saveName = desc;
+ writeSavegameHeader(out, header);
+
+ Common::Serializer s(nullptr, out);
+ synchronize(s);
+
+ out->finalize();
+ delete out;
+
+ return Common::kNoError;
+}
+
+void GnapEngine::synchronize(Common::Serializer &s) {
+ if (s.isSaving()) {
+ s.syncAsSint32LE(_currentSceneNum);
+ s.syncAsSint32LE(_prevSceneNum);
+ s.syncAsSint32LE(_cursorValue);
+ s.syncAsUint32LE(_inventory);
+ s.syncAsUint32LE(_gameFlags);
+ } else {
+ s.syncAsSint32LE(_newSceneNum);
+ s.syncAsSint32LE(_currentSceneNum);
+ s.syncAsSint32LE(_newCursorValue);
+ s.syncAsUint32LE(_inventory);
+ s.syncAsUint32LE(_gameFlags);
+
+ if (isFlag(kGFUnk24))
+ _timers[9] = 600;
+ }
+}
+
+const char *const SAVEGAME_STR = "GNAP";
+#define SAVEGAME_STR_SIZE 4
+void GnapEngine::writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header) {
+ // Write out a savegame header
+ out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
+
+ out->writeByte(GNAP_SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->writeString(header._saveName);
+ out->writeByte('\0');
+
+ // This implies the menu is used
+ // If we want to save/load at any time, then a check should be added
+ out->write(_tempThumbnail->getData(), _tempThumbnail->size());
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header) {
+ char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
+ header._thumbnail = nullptr;
+
+ // Validate the header Id
+ in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
+ if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
+ return false;
+
+ header._version = in->readByte();
+ if (header._version > GNAP_SAVEGAME_VERSION)
+ return false;
+
+ // Read in the string
+ header._saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header._saveName += ch;
+
+ // Get the thumbnail, saved in v2 or later
+ if (header._version == 1)
+ header._thumbnail = nullptr;
+ else {
+ header._thumbnail = Graphics::loadThumbnail(*in);
+ if (!header._thumbnail)
+ return false;
+ }
+
+ // Read in save date/time
+ header._year = in->readSint16LE();
+ header._month = in->readSint16LE();
+ header._day = in->readSint16LE();
+ header._hour = in->readSint16LE();
+ header._minute = in->readSint16LE();
+
+ return true;
+}
+
+Common::Error GnapEngine::loadGameState(int slot) {
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
+ generateSaveName(slot));
+ if (!saveFile)
+ return Common::kReadingFailed;
+
+ Common::Serializer s(saveFile, nullptr);
+
+ // Load the savegame header
+ GnapSavegameHeader header;
+ if (!readSavegameHeader(saveFile, header))
+ error("Invalid savegame");
+
+ if (header._thumbnail) {
+ header._thumbnail->free();
+ delete header._thumbnail;
+ }
+
+ synchronize(s);
+ delete saveFile;
+
+ _loadGameSlot = slot;
+ return Common::kNoError;
+}
+
+Common::String GnapEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+void GnapEngine::updateMenuStatusSaveGame() {
+#if 0
+ // NOTE:
+ // This is the code for the original screen game.
+ // It could be eventually fixed and could replace
+ // the ScummVM screens currently used.
+
+ char v43[30];
+ int v46;
+ v43[0] = '\0';
+ _hotspots[0]._x1 = 288;
+ _hotspots[0]._y1 = 74;
+ _hotspots[0]._x2 = 379;
+ _hotspots[0]._y2 = 96;
+ _sceneClickedHotspot = -1;
+
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ if (_hotspotsCount - 3 == _sceneClickedHotspot) {
+ // Button
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ _menuStatus = 1;
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ } else if (_hotspotsCount - 4 == _sceneClickedHotspot) {
+ // Cancel
+ _timers[2] = 10;
+ playSound(0x108F5, false);
+ _menuStatus = 1;
+ if (strcmp(v43, _savegameFilenames[_savegameIndex]) && _savegameIndex != -1) {
+ strcpy(_savegameFilenames[_savegameIndex], v43);
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ delayTicksCursor(5);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v16 = _gameSys->getSpriteWidthById(0x104F9);
+ warning("_savegameSprites[_savegameIndex] = allocSprite(v16, 40, 128, 0);");
+ }
+ } else if (_hotspotsCount - 5 == _sceneClickedHotspot) {
+ // OK
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ if (_savegameIndex != -1)
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ _menuStatus = 1;
+ } else if (_hotspotsCount - 1 == _sceneClickedHotspot) {
+ // in background
+ _menuDone = true;
+ } else if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) {
+ // Savegame name
+ _timers[2] = 10;
+ playSound(0x108F4, false);
+ if (strcmp(v43, _savegameFilenames[_savegameIndex]) & (_savegameIndex != -1)) {
+ strcpy(_savegameFilenames[_savegameIndex], v43);
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ delayTicksCursor(5);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v18 = _gameSys->getSpriteWidthById(0x104F9);
+ _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v18, 40);
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263);
+ }
+ _savegameIndex = _sceneClickedHotspot;
+ v46 = strlen(_savegameFilenames[_sceneClickedHotspot]);
+ strcpy(v43, _savegameFilenames[_sceneClickedHotspot]);
+ if (_cursorSprite == nullptr) {
+ int v19 = _gameSys->getTextHeight("_");
+ int v20 = _gameSys->getTextWidth("_");
+ _cursorSprite = _gameSys->allocSurface(v20, v19);
+ _gameSys->drawTextToSurface(_cursorSprite, 0, 0, 255, 0, 0, "_");
+ } else {
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ }
+ int v21 = _hotspots[_savegameIndex]._x2;
+ int v22 = v21 - _gameSys->getTextWidth("_");
+ if (v22 > _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288) {
+ int v25 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288;
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v25, _hotspots[_savegameIndex]._y1, 264);
+ } else {
+ int v23 = _hotspots[_savegameIndex]._x2;
+ int v24 = v23 - _gameSys->getTextWidth("_");
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v24, _hotspots[_savegameIndex]._y1, 264);
+ }
+ }
+
+ updateEvents();
+ Common::Event event;
+ _eventMan->pollEvent(event);
+
+ Common::KeyCode keycode = event.kbd.keycode;
+ if (_savegameIndex != -1 && keycode) {
+ if ((keycode < Common::KEYCODE_a || keycode > Common::KEYCODE_z) && (keycode < Common::KEYCODE_0 || keycode > Common::KEYCODE_9) && keycode != Common::KEYCODE_SPACE) {
+ if (keycode == Common::KEYCODE_BACKSPACE) {
+ if (v46 > 0)
+ --v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ if (_savegameSprites[_savegameIndex] != nullptr) {
+ _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263);
+ warning("memFreeHandle(_savegameSprites[_savegameIndex]);");
+ }
+ int v32 = _gameSys->getSpriteWidthById(0x104F9);
+ _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v32, 40);
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ int v33 = _hotspots[_savegameIndex]._y1;
+ int v34 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]);
+ _gameSys->insertSpriteDrawItem(_cursorSprite, _hotspots[_savegameIndex]._x1 + v34, v33, 264);
+ } else if (keycode == Common::KEYCODE_RETURN) {
+ _menuStatus = 1;
+ warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);");
+ }
+ } else {
+ _savegameFilenames[_savegameIndex][v46] = event.kbd.ascii;
+ if (v46 < 28)
+ ++v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ if (_gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) > 91) {
+ --v46;
+ _savegameFilenames[_savegameIndex][v46] = '\0';
+ }
+ _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]);
+ int v26 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]);
+ Common::Rect rect;
+ rect.right = _hotspots[_savegameIndex]._x1 + v26;
+ int v27 = rect.right;
+ rect.left = v27 - 2 * _gameSys->getTextWidth("W");
+ rect.top = _hotspots[_savegameIndex]._y1;
+ rect.bottom = _hotspots[_savegameIndex]._y2;
+ _gameSys->insertDirtyRect(rect);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ int v28 = _hotspots[_savegameIndex]._x2;
+ int v29 = _gameSys->getTextWidth("_");
+ if (v28 - v29 > rect.right)
+ _gameSys->insertSpriteDrawItem(_cursorSprite, rect.right, rect.top, 264);
+ else {
+ int v30 = _hotspots[_savegameIndex]._x2;
+ int v31 = v30 - _gameSys->getTextWidth("_");
+ _gameSys->insertSpriteDrawItem(_cursorSprite, v31, rect.top, 264);
+ }
+ clearKeyStatus1(8);
+ }
+ }
+
+// warning("keybChar = 0;");
+ if (_menuStatus == 1 || _menuDone) {
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ for (int i = 0; i < 7; ++i)
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ _gameSys->removeSpriteDrawItem(_cursorSprite, 264);
+ if (!_menuDone) {
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+ }
+#endif
+}
+
+void GnapEngine::updateMenuStatusLoadGame() {
+ _hotspots[0]._rect = Common::Rect(288, 74, 379, 96);
+ _sceneClickedHotspot = -1;
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+ if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) {
+ _timers[2] = 10;
+ if (_hotspotsCount - 4 <= _sceneClickedHotspot) {
+ playSound(0x108F5, false);
+ _gameSys->removeSpriteDrawItem(_menuSprite2, 262);
+ _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262);
+ for (int i = 0; i < 7; ++i)
+ _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263);
+ if (_hotspotsCount - 1 == _sceneClickedHotspot) {
+ _menuDone = true;
+ } else {
+ _menuStatus = 1;
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+ } else if (loadSavegame(_sceneClickedHotspot + 1)) {
+ playSound(0x108F5, false);
+ } else {
+ playSound(0x108F4, false);
+ _sceneDone = true;
+ }
+ }
+}
+
+void GnapEngine::updateMenuStatusQueryQuit() {
+ _hotspots[0]._rect = Common::Rect(311, 197, 377, 237);
+ _sceneClickedHotspot = -1;
+
+ if (!_timers[2])
+ _sceneClickedHotspot = getClickedHotspotId();
+
+ /* _sceneClickedHotspot
+ 0 Yes
+ 1 No
+ 2 Button
+ 3 Display
+ 4 Background
+ */
+
+ if (_sceneClickedHotspot == 0) {
+ // Quit the game
+ playSound(0x108F5, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _sceneDone = true;
+ _gameDone = true;
+ } else if (_sceneClickedHotspot == 4) {
+ // Exit the device
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _menuDone = true;
+ } else if (_sceneClickedHotspot != -1) {
+ // Return to the main menu
+ playSound(0x108F4, false);
+ _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262);
+ _timers[2] = 10;
+ _menuStatus = 1;
+ initMenuHotspots2();
+ _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262);
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/module.mk b/engines/gnap/module.mk
new file mode 100644
index 0000000000..ab507cbf94
--- /dev/null
+++ b/engines/gnap/module.mk
@@ -0,0 +1,32 @@
+MODULE := engines/gnap
+
+MODULE_OBJS := \
+ character.o \
+ datarchive.o \
+ debugger.o \
+ detection.o \
+ gamesys.o \
+ gnap.o \
+ grid.o \
+ menu.o \
+ music.o \
+ resource.o \
+ sound.o \
+ scenes/arcade.o \
+ scenes/groupcs.o \
+ scenes/group0.o \
+ scenes/group1.o \
+ scenes/group2.o \
+ scenes/group3.o \
+ scenes/group4.o \
+ scenes/group5.o \
+ scenes/intro.o \
+ scenes/scenecore.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_GNAP), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/gnap/music.cpp b/engines/gnap/music.cpp
new file mode 100644
index 0000000000..af33786a8f
--- /dev/null
+++ b/engines/gnap/music.cpp
@@ -0,0 +1,104 @@
+/* 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.
+ *
+ */
+
+// MIDI and digital music class
+
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
+#include "common/debug.h"
+#include "common/file.h"
+
+#include "gnap/music.h"
+#include "gnap/gnap.h"
+
+namespace Gnap {
+
+MusicPlayer::MusicPlayer(const char *filename) : _filename(filename) {
+
+ MidiPlayer::createDriver();
+
+ int ret = _driver->open();
+ if (ret == 0) {
+ if (_nativeMT32)
+ _driver->sendMT32Reset();
+ else
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
+}
+
+void MusicPlayer::sendToChannel(byte channel, uint32 b) {
+ if (!_channelsTable[channel]) {
+ _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ // If a new channel is allocated during the playback, make sure
+ // its volume is correctly initialized.
+ if (_channelsTable[channel])
+ _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
+ }
+
+ if (_channelsTable[channel])
+ _channelsTable[channel]->send(b);
+}
+
+void MusicPlayer::playSMF(bool loop) {
+ Common::StackLock lock(_mutex);
+
+ stop();
+
+ // Load MIDI resource data
+ Common::File musicFile;
+ musicFile.open(_filename);
+ if (!musicFile.isOpen()) {
+ debugC(2, kDebugMusic, "Cannot open music file %s", _filename.c_str());
+ return;
+ }
+ int midiMusicSize = musicFile.size();
+ free(_midiData);
+ _midiData = (byte *)malloc(midiMusicSize);
+ musicFile.read(_midiData, midiMusicSize);
+ musicFile.close();
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_midiData, midiMusicSize)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+
+ _parser = parser;
+
+ syncVolume();
+
+ _isLooping = loop;
+ _isPlaying = true;
+ } else {
+ debugC(2, kDebugMusic, "Cannot play music file %s", _filename.c_str());
+ delete parser;
+ }
+}
+
+void MusicPlayer::stop() {
+ Audio::MidiPlayer::stop();
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/music.h b/engines/gnap/music.h
new file mode 100644
index 0000000000..c5938937eb
--- /dev/null
+++ b/engines/gnap/music.h
@@ -0,0 +1,50 @@
+/* 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.
+ *
+ */
+
+// Music class
+
+#ifndef GNAP_MUSIC_H
+#define GNAP_MUSIC_H
+
+#include "audio/midiplayer.h"
+
+namespace Gnap {
+
+// Taken from Draci, which took it from MADE, which took it from SAGA.
+
+class MusicPlayer : public Audio::MidiPlayer {
+public:
+ MusicPlayer(const char *filename);
+
+ void playSMF(bool loop);
+ void stop();
+
+ // Overload Audio::MidiPlayer method
+ virtual void sendToChannel(byte channel, uint32 b);
+
+protected:
+ Common::String _filename;
+};
+
+} // End of namespace Gnap
+
+#endif
diff --git a/engines/gnap/resource.cpp b/engines/gnap/resource.cpp
new file mode 100644
index 0000000000..c6390082b1
--- /dev/null
+++ b/engines/gnap/resource.cpp
@@ -0,0 +1,125 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+
+namespace Gnap {
+
+// SequenceFrame
+
+void SequenceFrame::loadFromStream(Common::MemoryReadStream &stream) {
+ _duration = stream.readUint16LE();
+ _isScaled = (stream.readUint16LE() != 0);
+ _rect.left = stream.readUint32LE();
+ _rect.top = stream.readUint32LE();
+ _rect.right = stream.readUint32LE();
+ _rect.bottom = stream.readUint32LE();
+ _spriteId = stream.readUint32LE();
+ _soundId = stream.readUint32LE();
+
+ // Skip an unused value
+ stream.readUint32LE();
+
+ debugC(kDebugBasic, "SequenceFrame() spriteId: %d; soundId: %d", _spriteId, _soundId);
+}
+
+// SequenceAnimation
+
+void SequenceAnimation::loadFromStream(Common::MemoryReadStream &stream) {
+ // Skip two unused values
+ stream.readUint32LE();
+
+ _additionalDelay = stream.readUint32LE();
+ _framesCount = stream.readUint16LE();
+ _maxTotalDuration = stream.readUint16LE();
+ debugC(kDebugBasic, "SequenceAnimation() framesCount: %d", _framesCount);
+ frames = new SequenceFrame[_framesCount];
+ for (int i = 0; i < _framesCount; ++i)
+ frames[i].loadFromStream(stream);
+}
+
+// SequenceResource
+SequenceResource::SequenceResource(byte *data, uint32 size) {
+ Common::MemoryReadStream stream(data, size, DisposeAfterUse::NO);
+
+ // Skip an unused value
+ stream.readUint32LE();
+
+ _sequenceId = stream.readUint32LE();
+ _defaultId = stream.readUint32LE();
+ _sequenceId2 = stream.readUint32LE();
+ _defaultId2 = stream.readUint32LE();
+ _flags = stream.readUint32LE();
+ _totalDuration = stream.readUint32LE();
+ _xOffs = stream.readUint16LE();
+ _yOffs = stream.readUint16LE();
+ _animationsCount = stream.readUint32LE();
+ _animations = new SequenceAnimation[_animationsCount];
+ debugC(kDebugBasic, "SequenceResource() _animationsCount: %d", _animationsCount);
+ for (int i = 0; i < _animationsCount; ++i) {
+ uint32 animationOffs = stream.readUint32LE();
+ debugC(kDebugBasic, "animationOffs: %08X", animationOffs);
+ uint32 oldOffs = stream.pos();
+ stream.seek(animationOffs);
+ _animations[i].loadFromStream(stream);
+ stream.seek(oldOffs);
+ }
+}
+
+SequenceResource::~SequenceResource() {
+ delete[] _animations;
+}
+
+// SpriteResource
+SpriteResource::SpriteResource(byte *data, uint32 size) {
+ _data = data;
+ _width = READ_LE_UINT16(_data);
+ _height = READ_LE_UINT16(_data + 2);
+ _unknownVal1 = READ_LE_UINT16(_data + 4);
+ _unknownVal2 = READ_LE_UINT16(_data + 6);
+ _transparent = (READ_LE_UINT16(_data + 8) != 0);
+ _colorsCount = READ_LE_UINT16(_data + 10);
+ _palette = (uint32 *)(_data + 12);
+ _pixels = _data + 12 + _colorsCount * 4;
+#if defined(SCUMM_BIG_ENDIAN)
+ for (uint16 c = 0; c < _colorsCount; ++c)
+ _palette[c] = SWAP_BYTES_32(_palette[c]);
+#endif
+ debugC(kDebugBasic, "SpriteResource() width: %d; height: %d; colorsCount: %d", _width, _height, _colorsCount);
+}
+
+SpriteResource::~SpriteResource() {
+ delete[] _data;
+}
+
+// SoundResource
+SoundResource::SoundResource(byte *data, uint32 size) {
+ _data = data;
+ _size = size;
+}
+
+SoundResource::~SoundResource() {
+ delete[] _data;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/resource.h b/engines/gnap/resource.h
new file mode 100644
index 0000000000..f4a3669eda
--- /dev/null
+++ b/engines/gnap/resource.h
@@ -0,0 +1,190 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_RESOURCE_H
+#define GNAP_RESOURCE_H
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/str.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/system.h"
+
+#include "graphics/surface.h"
+
+#include "gnap/datarchive.h"
+
+namespace Gnap {
+
+enum {
+ kResTypeSprite = 0,
+ kResTypeBitmap = 1,
+ kResTypeSound = 2,
+ kResTypeSequence = 3
+};
+
+struct SequenceFrame {
+ int16 _duration;
+ bool _isScaled;
+ Common::Rect _rect;
+ int32 _spriteId;
+ int32 _soundId;
+ void loadFromStream(Common::MemoryReadStream &stream);
+};
+
+struct SequenceAnimation {
+ int32 _additionalDelay;
+ int16 _framesCount;
+ int16 _maxTotalDuration;
+ SequenceFrame *frames;
+
+ SequenceAnimation() : frames(nullptr), _additionalDelay(0), _framesCount(0), _maxTotalDuration(0) {}
+ ~SequenceAnimation() { delete[] frames; }
+ void loadFromStream(Common::MemoryReadStream &stream);
+};
+
+class SequenceResource {
+public:
+ SequenceResource(byte *data, uint32 size);
+ ~SequenceResource();
+public:
+ int32 _sequenceId;
+ int32 _defaultId;
+ int32 _sequenceId2;
+ uint32 _defaultId2;
+ uint32 _flags;
+ int32 _totalDuration;
+ int16 _xOffs;
+ int16 _yOffs;
+ int32 _animationsCount;
+ SequenceAnimation *_animations;
+};
+
+class SpriteResource {
+public:
+ SpriteResource(byte *data, uint32 size);
+ ~SpriteResource();
+public:
+ byte *_data;
+ byte *_pixels;
+ uint32 *_palette;
+ int16 _width, _height;
+ uint16 _unknownVal1;
+ uint16 _unknownVal2;
+ bool _transparent;
+ uint16 _colorsCount;
+};
+
+class SoundResource {
+public:
+ SoundResource(byte *data, uint32 size);
+ ~SoundResource();
+public:
+ byte *_data;
+ uint32 _size;
+};
+
+template <class ResourceClass, int ResourceType, bool FreeAfterLoad>
+class ResourceCacheTemplate {
+public:
+
+ ResourceCacheTemplate(DatManager *dat) : _dat(dat) {
+ }
+
+ ~ResourceCacheTemplate() {
+ }
+
+ ResourceClass *get(int resourceId) {
+ Resource *resource = find(resourceId);
+ if (!resource) {
+ debug(9, "Loading resource type %d with ID %08X from disk", ResourceType, resourceId);
+ resource = new Resource(load(resourceId));
+ _cache[resourceId] = resource;
+ } else {
+ debug(9, "Resource type %d with ID %08X was in cache", ResourceType, resourceId);
+ }
+ resource->_isLocked = true;
+ return resource->_obj;
+ }
+
+ void release(int resourceId) {
+ Resource *resource = find(resourceId);
+ if (resource)
+ resource->_isLocked = false;
+ }
+
+ void purge(bool force = false) {
+ for (CacheMapIterator it = _cache.begin(); it != _cache.end(); ++it) {
+ Resource *resource = it->_value;
+ if (force || !resource->_isLocked) {
+ delete resource;
+ _cache.erase(it);
+ }
+ }
+ }
+
+protected:
+
+ struct Resource {
+ ResourceClass *_obj;
+ bool _isLocked;
+ Resource(ResourceClass *obj) : _obj(obj), _isLocked(false) {}
+ ~Resource() { delete _obj; }
+ };
+
+ typedef Common::HashMap<int, Resource *> CacheMap;
+ typedef typename CacheMap::iterator CacheMapIterator;
+
+ DatManager *_dat;
+ CacheMap _cache;
+
+ Resource *find(int resourceId) {
+ CacheMapIterator it = _cache.find(resourceId);
+ if (it != _cache.end())
+ return it->_value;
+ return nullptr;
+ }
+
+ ResourceClass *load(int resourceId) {
+ if (_dat->getResourceType(resourceId) != ResourceType)
+ error("ResourceCache::load() Wrong resource type: Expected %d, got %d", ResourceType, _dat->getResourceType(resourceId));
+
+ byte *resourceData = _dat->loadResource(resourceId);
+ uint32 resourceSize = _dat->getResourceSize(resourceId);
+ ResourceClass *obj = new ResourceClass(resourceData, resourceSize);
+ if (FreeAfterLoad)
+ delete[] resourceData;
+ return obj;
+ }
+
+};
+
+typedef ResourceCacheTemplate<SpriteResource, kResTypeSprite, false> SpriteCache;
+typedef ResourceCacheTemplate<SoundResource, kResTypeSound, false> SoundCache;
+typedef ResourceCacheTemplate<SequenceResource, kResTypeSequence, true> SequenceCache;
+
+} // End of namespace Gnap
+
+#endif // GNAP_RESOURCE_H
diff --git a/engines/gnap/scenes/arcade.cpp b/engines/gnap/scenes/arcade.cpp
new file mode 100644
index 0000000000..db4999cb43
--- /dev/null
+++ b/engines/gnap/scenes/arcade.cpp
@@ -0,0 +1,2729 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/arcade.h"
+
+namespace Gnap {
+
+static const ObstacleDef kObstacleDefs[] = {
+ {0xB4, 15}, {0xCB, 14}, {0xCD, 13}, {0xCF, 15}, {0xBA, 14},
+ {0xCD, 13}, {0xCF, 12}, {0xCB, 15}, {0xBD, 13}, {0xCF, 12},
+ {0xCD, 11}, {0xCB, 15}, {0xB7, 12}, {0xCD, 11}, {0xCB, 10},
+ {0xCF, 15}, {0xCF, 14}, {0xBD, 13}, {0xCF, 12}, {0xCD, 11},
+ {0xCB, 15}, {0xCB, 13}, {0xB4, 12}, {0xCB, 11}, {0xCD, 10},
+ {0xCF, 15}, {0xCD, 12}, {0xBA, 12}, {0xCD, 12}, {0xCF, 12},
+ {0xCB, 15}, {0xCB, 9}, {0xCD, 9}, {0xCF, 9}, {0xCD, 9},
+ {0xCB, 9}, {0xCD, 9}, {0xCF, 5}, {0xBD, 13}, {0xCF, 8},
+ {0xCB, 8}, {0xCD, 15}, {0xB4, 1}, {0xBD, 7}, {0xCF, 7},
+ {0xCD, 7}, {0xCB, 7}, {0xCD, 7}, {0xCF, 15}, {0xCF, 15}
+};
+
+Scene49::Scene49(GnapEngine *vm) : Scene(vm) {
+ _scoreBarFlash = false;
+ _scoreBarPos = -1;
+ _scoreLevel = -1;
+ _obstacleIndex = -1;
+ _truckSequenceId = -1;
+ _truckId = -1;
+ _truckLaneNum = -1;
+
+ for (int i = 0; i < 5; i++) {
+ _obstacles[i]._currSequenceId = -1;
+ _obstacles[i]._closerSequenceId = -1;
+ _obstacles[i]._passedSequenceId = -1;
+ _obstacles[i]._splashSequenceId = -1;
+ _obstacles[i]._collisionSequenceId = -1;
+ _obstacles[i]._prevId = -1;
+ _obstacles[i]._currId = -1;
+ _obstacles[i]._laneNum = -1;
+ }
+}
+
+int Scene49::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ for (int i = 0; i < 5; ++i)
+ gameSys.setAnimation(0, 0, i + 2);
+ _vm->_timers[2] = 0;
+ _vm->_timers[0] = 0;
+ _vm->_timers[1] = 0;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ return 0xD5;
+}
+
+void Scene49::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene49::checkObstacles() {
+ if (_vm->_timers[2] == 0) {
+ if (_vm->_timers[3] == 0) {
+ for (int i = 0; i < 5; ++i)
+ clearObstacle(i);
+ }
+
+ for (int j = 0; j < 5; ++j) {
+ if (_obstacles[j]._currSequenceId == 0) {
+ _vm->_timers[3] = 35;
+ _obstacles[j]._currSequenceId = kObstacleDefs[_obstacleIndex]._sequenceId;
+ switch (_obstacles[j]._currSequenceId) {
+ case 0xB4:
+ _obstacles[j]._laneNum = 1;
+ _obstacles[j]._closerSequenceId = 180;
+ _obstacles[j]._passedSequenceId = 181;
+ _obstacles[j]._splashSequenceId = 182;
+ _obstacles[j]._collisionSequenceId = 192;
+ break;
+ case 0xB7:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 183;
+ _obstacles[j]._passedSequenceId = 184;
+ _obstacles[j]._splashSequenceId = 185;
+ _obstacles[j]._collisionSequenceId = 193;
+ break;
+ case 0xBD:
+ _obstacles[j]._laneNum = 3;
+ _obstacles[j]._closerSequenceId = 189;
+ _obstacles[j]._passedSequenceId = 190;
+ _obstacles[j]._splashSequenceId = 191;
+ _obstacles[j]._collisionSequenceId = 195;
+ break;
+ case 0xBA:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 186;
+ _obstacles[j]._passedSequenceId = 187;
+ _obstacles[j]._splashSequenceId = 188;
+ _obstacles[j]._collisionSequenceId = 194;
+ break;
+ case 0xCB:
+ _obstacles[j]._laneNum = 1;
+ _obstacles[j]._closerSequenceId = 203;
+ _obstacles[j]._passedSequenceId = 204;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 209;
+ break;
+ case 0xCD:
+ _obstacles[j]._laneNum = 2;
+ _obstacles[j]._closerSequenceId = 205;
+ _obstacles[j]._passedSequenceId = 206;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 210;
+ break;
+ case 0xCF:
+ _obstacles[j]._laneNum = 3;
+ _obstacles[j]._closerSequenceId = 207;
+ _obstacles[j]._passedSequenceId = 208;
+ _obstacles[j]._splashSequenceId = 0;
+ _obstacles[j]._collisionSequenceId = 211;
+ break;
+ }
+ _obstacles[j]._prevId = _truckId;
+ _obstacles[j]._currId = _obstacles[j]._prevId;
+ _vm->_gameSys->setAnimation(_obstacles[j]._currSequenceId, _obstacles[j]._currId, j + 2);
+ _vm->_gameSys->insertSequence(_obstacles[j]._currSequenceId, _obstacles[j]._currId, 0, 0, kSeqNone, 0, 0, -50);
+ _vm->_timers[2] = kObstacleDefs[_obstacleIndex]._ticks;
+ ++_obstacleIndex;
+ if (_obstacleIndex == 50)
+ _obstacleIndex = 0;
+ break;
+ }
+ }
+ }
+}
+
+void Scene49::updateObstacle(int id) {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ Scene49Obstacle &obstacle = _obstacles[id];
+ obstacle._currId = obstacle._prevId;
+
+ switch (obstacle._laneNum) {
+ case 1:
+ obstacle._prevId = _truckId + 1;
+ break;
+ case 2:
+ if (_truckLaneNum != 2 && _truckLaneNum != 3)
+ obstacle._prevId = _truckId - 1;
+ else
+ obstacle._prevId = _truckId + 1;
+ break;
+ case 3:
+ if (_truckLaneNum != 1 && _truckLaneNum != 2)
+ obstacle._prevId = _truckId;
+ else
+ obstacle._prevId = _truckId - 1;
+ break;
+ }
+
+ if (obstacle._currSequenceId == obstacle._closerSequenceId) {
+ if (_truckLaneNum == obstacle._laneNum) {
+ if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._collisionSequenceId;
+ _vm->playSound(0xE0, false);
+ increaseScore(30);
+ } else if ((obstacle._laneNum == 1 && _truckSequenceId == 0xB0) ||
+ (obstacle._laneNum == 2 && (_truckSequenceId == 0xB1 || _truckSequenceId == 0xB2)) ||
+ (obstacle._laneNum == 3 && _truckSequenceId == 0xB3)) {
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ } else {
+ gameSys.setAnimation(obstacle._collisionSequenceId, 256, 0);
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ gameSys.insertSequence(obstacle._collisionSequenceId, 256,
+ _truckSequenceId, _truckId,
+ kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = obstacle._collisionSequenceId;
+ _truckId = 256;
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ _vm->playSound(0xE1, false);
+ decreaseScore(30);
+ }
+ } else {
+ gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._passedSequenceId;
+ }
+ } else if (obstacle._currSequenceId == obstacle._passedSequenceId) {
+ if (_truckLaneNum == obstacle._laneNum) {
+ if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._collisionSequenceId;
+ _vm->playSound(0xE0, false);
+ increaseScore(30);
+ }
+ } else if (obstacle._splashSequenceId) {
+ gameSys.setAnimation(obstacle._splashSequenceId, obstacle._prevId, id + 2);
+ gameSys.insertSequence(obstacle._splashSequenceId, obstacle._prevId,
+ obstacle._currSequenceId, obstacle._currId,
+ kSeqSyncWait, 0, 0, -50);
+ obstacle._currSequenceId = obstacle._splashSequenceId;
+ }
+ } else {
+ gameSys.setAnimation(0, 0, id + 2);
+ clearObstacle(id);
+ }
+}
+
+void Scene49::increaseScore(int amount) {
+ if (_scoreBarPos + amount <= 556) {
+ _scoreBarPos += amount;
+ _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 255, 0, 0);
+ }
+
+ _scoreLevel = (_scoreBarPos + amount >= 556) ? 1 : 0;
+}
+
+void Scene49::decreaseScore(int amount) {
+ if (_scoreBarPos >= 226 && _scoreLevel == 0) {
+ if (_scoreBarFlash)
+ refreshScoreBar();
+ _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 89, 0, 5);
+ _scoreBarPos -= amount;
+ _scoreLevel = 0;
+ }
+}
+
+void Scene49::refreshScoreBar() {
+ if (_scoreBarFlash)
+ _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 255, 0, 0);
+ else
+ _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 89, 0, 5);
+ _scoreBarFlash = !_scoreBarFlash;
+}
+
+void Scene49::clearObstacle(int index) {
+ _obstacles[index]._currSequenceId = 0;
+ _obstacles[index]._closerSequenceId = 0;
+ _obstacles[index]._passedSequenceId = 0;
+ _obstacles[index]._splashSequenceId = 0;
+ _obstacles[index]._collisionSequenceId = 0;
+ _obstacles[index]._prevId = 0;
+ _obstacles[index]._currId = 0;
+ _obstacles[index]._laneNum = 0;
+}
+
+void Scene49::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ bool animToggle6 = false;
+ bool animToggle5 = false;
+ bool animToggle4 = false;
+ bool animToggle3 = false;
+ bool streetAnimToggle = false;
+ bool bgAnimToggle = false;
+
+ _vm->playSound(0xE2, true);
+ _vm->setSoundVolume(0xE2, 75);
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+
+ _scoreBarPos = 196;
+ _scoreLevel = 0;
+ _scoreBarFlash = false;
+
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _truckSequenceId = 0xAD;
+ _truckLaneNum = 1;
+ break;
+ case 1:
+ _truckSequenceId = 0xAE;
+ _truckLaneNum = 2;
+ break;
+ case 2:
+ _truckSequenceId = 0xAF;
+ _truckLaneNum = 3;
+ break;
+ }
+
+ int bgWidth1 = gameSys.getSpriteWidthById(0x5E);
+ int bgX1 = 600;
+
+ int bgWidth2 = gameSys.getSpriteWidthById(0x5F);
+ int bgX2 = 400;
+
+ int bgWidth3 = gameSys.getSpriteWidthById(4);
+ int bgX3 = 700;
+
+ int bgWidth4 = gameSys.getSpriteWidthById(5);
+ int bgX4 = 500;
+
+ int bgWidth5 = gameSys.getSpriteWidthById(6);
+ int bgX5 = 300;
+
+ int bgWidth6 = gameSys.getSpriteWidthById(7);
+ int bgX6 = 100;
+
+ gameSys.setAnimation(0xC8, 251, 1);
+ gameSys.setAnimation(_truckSequenceId, 256, 0);
+ gameSys.insertSequence(0xC9, 256, 0, 0, kSeqNone, 0, 600, 85);
+ gameSys.insertSequence(0xCA, 257, 0, 0, kSeqNone, 0, 400, 100);
+ gameSys.insertSequence(0xC4, 256, 0, 0, kSeqNone, 0, 700, 140);
+ gameSys.insertSequence(0xC5, 257, 0, 0, kSeqNone, 0, 500, 160);
+ gameSys.insertSequence(0xC6, 258, 0, 0, kSeqNone, 0, 300, 140);
+ gameSys.insertSequence(0xC7, 259, 0, 0, kSeqNone, 0, 100, 140);
+ gameSys.insertSequence(0xC8, 251, 0, 0, kSeqNone, 0, 0, -50);
+ gameSys.insertSequence(_truckSequenceId, 256, 0, 0, kSeqNone, 0, 0, -50);
+
+ _vm->_timers[0] = 2;
+
+ for (int i = 0; i < 5; ++i)
+ clearObstacle(i);
+
+ _obstacleIndex = 0;
+
+ _vm->_timers[2] = _vm->getRandom(20) + 10;
+
+ _truckId = 256;
+ _vm->_timers[3] = 35;
+
+ while (!_vm->_sceneDone) {
+ if (_vm->_timers[0] == 0) {
+ // Update background animations (clouds etc.)
+ --bgX1;
+ bgX2 -= 2;
+ bgX3 -= 5;
+ --bgX4;
+ --bgX5;
+ --bgX6;
+ if (bgX1 <= -bgWidth1)
+ bgX1 = 799;
+ if (bgX2 <= -bgWidth2)
+ bgX2 = 799;
+ if (bgX3 <= -bgWidth3)
+ bgX3 = 799;
+ if (bgX4 <= -bgWidth4)
+ bgX4 = 799;
+ if (bgX5 <= -bgWidth5)
+ bgX5 = 799;
+ if (bgX6 <= -bgWidth6)
+ bgX6 = 799;
+ bgAnimToggle = !bgAnimToggle;
+ gameSys.insertSequence(0xC9, (bgAnimToggle ? 1 : 0) + 256, 0xC9, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX1, 85);
+ gameSys.insertSequence(0xCA, (bgAnimToggle ? 1 : 0) + 257, 0xCA, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX2, 100);
+ gameSys.insertSequence(0xC4, (bgAnimToggle ? 1 : 0) + 256, 0xC4, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX3, 140);
+ gameSys.insertSequence(0xC5, (bgAnimToggle ? 1 : 0) + 257, 0xC5, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX4, 160);
+ gameSys.insertSequence(0xC6, (bgAnimToggle ? 1 : 0) + 258, 0xC6, (bgAnimToggle ? 0 : 1) + 258, kSeqSyncWait, 0, bgX5, 140);
+ gameSys.insertSequence(0xC7, (bgAnimToggle ? 1 : 0) + 259, 0xC7, (bgAnimToggle ? 0 : 1) + 259, kSeqSyncWait, 0, bgX6, 140);
+ _vm->_timers[0] = 2;
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ streetAnimToggle = !streetAnimToggle;
+ gameSys.setAnimation(0xC8, (streetAnimToggle ? 1 : 0) + 251, 1);
+ gameSys.insertSequence(0xC8, (streetAnimToggle ? 1 : 0) + 251, 200, (streetAnimToggle ? 0 : 1) + 251, kSeqSyncWait, 0, 0, -50);
+ }
+
+ checkObstacles();
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (_truckSequenceId) {
+ case 0xB1:
+ _truckLaneNum = 1;
+ break;
+ case 0xB0:
+ case 0xB3:
+ _truckLaneNum = 2;
+ break;
+ case 0xB2:
+ _truckLaneNum = 3;
+ break;
+ }
+ animToggle3 = !animToggle3;
+ if (_truckLaneNum == 1) {
+ gameSys.setAnimation(0xAD, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAD, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAD;
+ } else if (_truckLaneNum == 2) {
+ gameSys.setAnimation(0xAE, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAE, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAE;
+ } else {
+ gameSys.setAnimation(0xAF, (animToggle3 ? 1 : 0) + 256, 0);
+ gameSys.insertSequence(0xAF, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50);
+ _truckSequenceId = 0xAF;
+ }
+ _truckId = (animToggle3 ? 1 : 0) + 256;
+ if (_scoreLevel == 1) {
+ if (!gameSys.isSequenceActive(0xD4, 266)) {
+ gameSys.setAnimation(0xD4, 266, 8);
+ gameSys.insertSequence(0xD4, 266, 0, 0, kSeqNone, 0, 0, -50);
+ }
+ ++_scoreLevel;
+ _vm->_timers[1] = 2;
+ animToggle4 = false;
+ animToggle5 = false;
+ animToggle6 = false;
+ _scoreBarFlash = false;
+ }
+ }
+
+ if (_scoreLevel != 0 && !_vm->_timers[1]) {
+ refreshScoreBar();
+ _vm->_timers[1] = 8;
+ if (animToggle6) {
+ if (animToggle5) {
+ if (animToggle4 && !gameSys.isSequenceActive(212, 266))
+ gameSys.insertSequence(212, 266, 0, 0, kSeqNone, 0, 0, -50);
+ animToggle4 = !animToggle4;
+ }
+ animToggle5 = !animToggle5;
+ }
+ animToggle6 = !animToggle6;
+ }
+
+ updateAnimations();
+
+ if (clearKeyStatus()) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 2;
+ _vm->_newCursorValue = 1;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) {
+ // Steer right
+ if (_truckSequenceId == 0xB3)
+ _truckLaneNum = 2;
+ if (_truckSequenceId == 0xB1)
+ _truckLaneNum = 1;
+ if (_truckLaneNum != 3 && _truckLaneNum != 2) {
+ if (_scoreLevel) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 47;
+ }
+ } else {
+ int steerSequenceId = (_truckLaneNum == 3) ? 0xB3 : 0xB1;
+ if (_truckSequenceId == 0xAE || _truckSequenceId == 0xAF) {
+ gameSys.setAnimation(steerSequenceId, 256, 0);
+ gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = steerSequenceId;
+ _truckId = 256;
+ }
+ }
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) {
+ // Steer left
+ if (_truckSequenceId == 0xB0)
+ _truckLaneNum = 2;
+ if (_truckSequenceId == 0xB2)
+ _truckLaneNum = 3;
+ if (_truckLaneNum == 1 || _truckLaneNum == 2) {
+ int steerSequenceId = (_truckLaneNum == 1) ? 0xB0 : 0xB2;
+ if (_truckSequenceId == 0xAD || _truckSequenceId == 0xAE) {
+ gameSys.setAnimation(steerSequenceId, 256, 0);
+ gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50);
+ _truckSequenceId = steerSequenceId;
+ _truckId = 256;
+ }
+ }
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ }
+ _vm->gameUpdateTick();
+ }
+ _vm->stopSound(0xE2);
+}
+
+void Scene49::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ for (int i = 0; i < 5; ++i) {
+ if (gameSys.getAnimationStatus(i + 2) == 2) {
+ if (_obstacles[i]._currSequenceId)
+ updateObstacle(i);
+ }
+ }
+
+ if (gameSys.getAnimationStatus(8) == 2) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 47;
+ }
+}
+
+/*****************************************************************************/
+
+Scene50::Scene50(GnapEngine *vm) : Scene(vm) {
+ _fightDone = false;
+
+ _roundNum = -1;
+ _timeRemaining = -1;
+ _leftTongueRoundsWon = -1;
+ _rightTongueRoundsWon = -1;
+ _leftTongueSequenceId = -1;
+ _leftTongueId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueNextId = -1;
+ _rightTongueSequenceId = -1;
+ _rightTongueId = -1;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueNextId = -1;
+ _leftTongueEnergy = -1;
+ _rightTongueEnergy = -1;
+
+ _timesPlayed = 0;
+ _timesPlayedModifier = 0;
+ _attackCounter = 0;
+ _leftTongueEnergyBarPos = 10;
+ _leftTongueNextIdCtr = 0;
+ _rightTongueEnergyBarPos = 10;
+ _rightTongueNextIdCtr = 0;
+}
+
+int Scene50::init() {
+ return 0xC7;
+}
+
+void Scene50::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+bool Scene50::tongueWinsRound(int tongueNum) {
+ if (tongueNum == 1)
+ ++_leftTongueRoundsWon;
+ else
+ ++_rightTongueRoundsWon;
+ playWinBadgeAnim(tongueNum);
+ bool fightOver = _rightTongueRoundsWon == 2 || _leftTongueRoundsWon == 2;
+ playWinAnim(tongueNum, fightOver);
+ return fightOver;
+}
+
+void Scene50::playWinAnim(int tongueNum, bool fightOver) {
+ if (tongueNum == 1) {
+ if (fightOver) {
+ _vm->_gameSys->insertSequence(0xAD, 140, 0xAC, 140, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xB4;
+ _rightTongueSequenceId = 0xBC;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB4, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ _vm->invAdd(kItemGum);
+ _vm->setFlag(kGFUnk13);
+ } else {
+ _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xB4;
+ _rightTongueSequenceId = 0xBC;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB4, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ }
+ } else {
+ _vm->_gameSys->insertSequence(0xBE, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->setAnimation(0xBE, 100, 5);
+ waitForAnim(5);
+ _vm->_gameSys->insertSequence(0xBF, 100, 0xBE, 100, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB5, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _rightTongueSequenceId = 0xBF;
+ _leftTongueSequenceId = 0xB5;
+ _rightTongueId = 100;
+ _leftTongueId = 100;
+ _vm->_gameSys->setAnimation(0xB5, 100, 6);
+ _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5);
+ waitForAnim(6);
+ waitForAnim(5);
+ }
+ _vm->delayTicksA(1, 7);
+}
+
+void Scene50::delayTicks() {
+ _vm->delayTicksA(3, 7);
+}
+
+void Scene50::initRound() {
+ _leftTongueEnergy = 10;
+ _rightTongueEnergy = 10;
+ _fightDone = false;
+ _vm->_timers[3] = getRightTongueActionTicks();
+ _vm->_timers[4] = 0;
+ _vm->_timers[6] = 0;
+ _vm->_gameSys->fillSurface(nullptr, 91, 73, 260, 30, 212, 0, 0);
+ _vm->_gameSys->fillSurface(nullptr, 450, 73, 260, 30, 212, 0, 0);
+ _timeRemaining = 40;
+ drawCountdown(40);
+}
+
+bool Scene50::updateCountdown() {
+ if (!_vm->_timers[5]) {
+ --_timeRemaining;
+ if (_timeRemaining < 0) {
+ return true;
+ } else {
+ _vm->_timers[5] = 15;
+ drawCountdown(_timeRemaining);
+ }
+ }
+ return false;
+}
+
+void Scene50::drawCountdown(int value) {
+ char str[8];
+ sprintf(str, "%02d", value);
+ _vm->_gameSys->fillSurface(nullptr, 371, 505, 50, 27, 0, 0, 0);
+ _vm->_gameSys->drawTextToSurface(nullptr, 381, 504, 255, 255, 255, str);
+}
+
+void Scene50::playTonguesIdle() {
+ _vm->_gameSys->insertSequence(0xBA, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xC2, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = 0xBA;
+ _rightTongueSequenceId = 0xC2;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = 100;
+ _rightTongueId = 100;
+ _vm->_gameSys->setAnimation(0xC2, 100, 5);
+ _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6);
+}
+
+void Scene50::playRoundAnim(int roundNum) {
+ int sequenceId = 0;
+
+ switch (roundNum) {
+ case 1:
+ sequenceId = 0xAF;
+ break;
+ case 2:
+ sequenceId = 0xB0;
+ break;
+ case 3:
+ sequenceId = 0xB1;
+ break;
+ }
+
+ _vm->_gameSys->insertSequence(sequenceId, 256, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->setAnimation(sequenceId, 256, 7);
+ waitForAnim(7);
+
+ _vm->_gameSys->insertSequence(0xAB, 256, sequenceId, 256, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->setAnimation(0xAB, 256, 7);
+ waitForAnim(7);
+}
+
+bool Scene50::updateEnergyBars(int newLeftBarPos, int newRightBarPos) {
+ if (newLeftBarPos != _leftTongueEnergyBarPos) {
+ if (newLeftBarPos < 0)
+ newLeftBarPos = 0;
+ _leftTongueEnergyBarPos = newLeftBarPos;
+ _vm->_gameSys->fillSurface(nullptr, 26 * newLeftBarPos + 91, 73, 260 - 26 * newLeftBarPos, 30, 0, 0, 0);
+ }
+
+ if (newRightBarPos != _rightTongueEnergyBarPos) {
+ if (newRightBarPos < 0)
+ newRightBarPos = 0;
+ _rightTongueEnergyBarPos = newRightBarPos;
+ if (newRightBarPos != 10)
+ _vm->_gameSys->fillSurface(nullptr, 26 * (9 - newRightBarPos) + 450, 73, 26, 30, 0, 0, 0);
+ }
+
+ if (newLeftBarPos * newRightBarPos > 0)
+ return false;
+
+ _leftTongueEnergyBarPos = 10;
+ _rightTongueEnergyBarPos = 10;
+ return true;
+}
+
+void Scene50::waitForAnim(int animationIndex) {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gameSys.setAnimation(0, 0, animationIndex);
+}
+
+int Scene50::checkInput() {
+ int sequenceId = -1;
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ sequenceId = 0xB6;
+ } else if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ sequenceId = 0xB3;
+ } else if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _fightDone = true;
+ }
+
+ return sequenceId;
+}
+
+int Scene50::getRightTongueAction() {
+ int sequenceId = -1;
+
+ if (!_vm->_timers[3]) {
+ _vm->_timers[3] = getRightTongueActionTicks();
+ if (_rightTongueEnergy >= _leftTongueEnergy) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ sequenceId = 0xBE;
+ break;
+ case 1:
+ sequenceId = 0xBE;
+ break;
+ case 2:
+ sequenceId = 0xBB;
+ break;
+ case 3:
+ sequenceId = 0xBB;
+ break;
+ case 4:
+ sequenceId = 0xBB;
+ break;
+ }
+ } else {
+ switch (_vm->getRandom(4)) {
+ case 0:
+ sequenceId = 0xBE;
+ break;
+ case 1:
+ sequenceId = 0xBB;
+ break;
+ case 2:
+ sequenceId = 0xBE;
+ break;
+ case 3:
+ sequenceId = 0xBE;
+ break;
+ }
+ }
+ }
+
+ return sequenceId;
+}
+
+void Scene50::updateAnimations() {
+ if (!_vm->_timers[4])
+ _attackCounter = 0;
+
+ if (_vm->_gameSys->getAnimationStatus(5) == 2) {
+ if (_rightTongueSequenceId == 0xBE) {
+ if (_leftTongueSequenceId != 0xB3 && _leftTongueSequenceId != 0xB8)
+ _rightTongueNextSequenceId = 0xBF;
+ else
+ _rightTongueNextSequenceId = 0xC0;
+ }
+ if (_rightTongueNextSequenceId == -1)
+ _rightTongueNextSequenceId = 0xC2;
+ if (_rightTongueNextSequenceId == 0xBF) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5);
+ _vm->_gameSys->setAnimation(0xB9, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xB9, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncExists, 0, 0, 0);
+ _rightTongueSequenceId = _rightTongueNextSequenceId;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueSequenceId = 0xB9;
+ _leftTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ _leftTongueId = _leftTongueNextId;
+ _leftTongueEnergy -= _vm->getRandom(1) + 1;
+ } else {
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5);
+ _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0);
+ _rightTongueSequenceId = _rightTongueNextSequenceId;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ }
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(6) == 2) {
+ if (_leftTongueSequenceId == 0xB6) {
+ ++_attackCounter;
+ if (_timesPlayedModifier + 3 <= _attackCounter) {
+ _leftTongueNextSequenceId = 0xB8;
+ } else {
+ _vm->_timers[4] = 20;
+ if (_rightTongueSequenceId != 0xBB && _rightTongueSequenceId != 0xC0 && _vm->getRandom(7) != _roundNum)
+ _leftTongueNextSequenceId = 0xB7;
+ else
+ _leftTongueNextSequenceId = 0xB8;
+ }
+ }
+ if (_leftTongueNextSequenceId == 0xB3)
+ --_attackCounter;
+ if (_leftTongueNextSequenceId == -1)
+ _leftTongueNextSequenceId = 0xBA;
+ if (_leftTongueNextSequenceId == 0xB7) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->setAnimation(0xC1, _rightTongueNextId, 5);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xC1, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0);
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _rightTongueSequenceId = 0xC1;
+ _rightTongueNextSequenceId = -1;
+ _rightTongueId = _rightTongueNextId;
+ _leftTongueId = _leftTongueNextId;
+ --_rightTongueEnergy;
+ } else if (_leftTongueNextSequenceId != 0xB8 || _rightTongueSequenceId != 0xC2) {
+ _leftTongueNextId = getLeftTongueNextId();
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = _leftTongueNextId;
+ } else {
+ _leftTongueNextId = getLeftTongueNextId();
+ _rightTongueNextId = getRightTongueNextId();
+ _vm->_gameSys->setAnimation(0xBB, _rightTongueNextId, 5);
+ _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0);
+ _vm->_gameSys->insertSequence(0xBB, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0);
+ _rightTongueSequenceId = 0xBB;
+ _rightTongueId = _rightTongueNextId;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueSequenceId = _leftTongueNextSequenceId;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = _leftTongueNextId;
+ }
+ }
+}
+
+int Scene50::getRightTongueActionTicks() {
+ return 15 - 5 * _roundNum + 1;
+}
+
+int Scene50::getLeftTongueNextId() {
+ _leftTongueNextIdCtr = (_leftTongueNextIdCtr + 1) % 3;
+ return _leftTongueNextIdCtr + 100;
+}
+
+int Scene50::getRightTongueNextId() {
+ _rightTongueNextIdCtr = (_rightTongueNextIdCtr + 1) % 3;
+ return _rightTongueNextIdCtr + 100;
+}
+
+void Scene50::playWinBadgeAnim(int tongueNum) {
+ int sequenceId;
+
+ if (tongueNum == 1) {
+ if (_leftTongueRoundsWon == 1)
+ sequenceId = 0xC3;
+ else
+ sequenceId = 0xC4;
+ } else {
+ if (_rightTongueRoundsWon == 1)
+ sequenceId = 0xC5;
+ else
+ sequenceId = 0xC6;
+ }
+
+ _vm->_gameSys->setAnimation(sequenceId, 120, 7);
+ _vm->_gameSys->insertSequence(sequenceId, 120, 0, 0, kSeqNone, 0, 0, 0);
+ waitForAnim(7);
+}
+
+void Scene50::run() {
+ ++_timesPlayed;
+ _timesPlayedModifier = _timesPlayed / 4;
+ _leftTongueRoundsWon = 0;
+ _rightTongueRoundsWon = 0;
+ _leftTongueSequenceId = 186;
+ _rightTongueSequenceId = 194;
+ _rightTongueNextSequenceId = -1;
+ _leftTongueNextSequenceId = -1;
+ _leftTongueId = 100;
+ _rightTongueId = 100;
+
+ _vm->_gameSys->setAnimation(194, 100, 5);
+ _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6);
+ _vm->_gameSys->insertSequence(_leftTongueSequenceId, _leftTongueId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->insertSequence(_rightTongueSequenceId, _rightTongueId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_gameSys->insertSequence(172, 140, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+
+ initRound();
+
+ _roundNum = 1;
+
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+
+ _vm->delayTicksA(1, 7);
+
+ playRoundAnim(_roundNum);
+
+ _vm->_timers[5] = 15;
+
+ while (!_fightDone && !_vm->_gameDone) {
+ int playerSequenceId = checkInput();
+ if (playerSequenceId != -1)
+ _leftTongueNextSequenceId = playerSequenceId;
+
+ int rightSequenceId = getRightTongueAction();
+ if (rightSequenceId != -1)
+ _rightTongueNextSequenceId = rightSequenceId;
+
+ updateAnimations();
+
+ if (updateCountdown() ||
+ updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy)) {
+ bool v0;
+ if (_rightTongueEnergy < _leftTongueEnergy)
+ v0 = tongueWinsRound(1);
+ else
+ v0 = tongueWinsRound(2);
+ if (v0) {
+ delayTicks();
+ _fightDone = true;
+ } else {
+ ++_roundNum;
+ initRound();
+ playTonguesIdle();
+ updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy);
+ playRoundAnim(_roundNum);
+ _vm->_timers[5] = 15;
+ }
+ }
+ _vm->gameUpdateTick();
+ }
+
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ _vm->_gameSys->setAnimation(0, 0, 6);
+ _vm->_gameSys->setAnimation(0, 0, 5);
+ _vm->_gameSys->setAnimation(0, 0, 3);
+
+ _vm->showCursor();
+}
+
+/*****************************************************************************/
+
+static const int kDigitSequenceIds[] = {
+ 0xCA, 0xCB, 0xCC, 0xCD, 0xCE,
+ 0xCF, 0xD0, 0xD1, 0xD2, 0xD3
+};
+
+static const int kDigitPositions[4] = {
+ 0, 34, 83, 119
+};
+
+/*
+ 0xBA Falling banana peel
+ 0xBC Banana peel goes away
+ 0xBD Falling coin
+ 0xBE Fallen coin
+ 0xC0 Falling banknote
+ 0xB6 Platypus tripping (right)
+ 0xB7 Platypus tripping (left)
+ 0x76 Platypus jumping (right)
+*/
+
+Scene51::Scene51(GnapEngine *vm) : Scene(vm) {
+ _dropLoseCash = false;
+
+ _cashAmount = -1;
+ _guySequenceId = -1;
+ _guyNextSequenceId = -1;
+ _itemsCaughtCtr = -1;
+ _dropSpeedTicks = -1;
+ _nextDropItemKind = -1;
+ _itemInsertX = -1;
+ _itemInsertDirection = -1;
+ _platypusSequenceId = -1;
+ _platypusNextSequenceId = -1;
+ _platypusJumpSequenceId = -1;
+ _itemsCtr = -1;
+ _itemsCtr1 = -1;
+ _itemsCtr2 = -1;
+
+ for (int i = 0; i < 4; i++) {
+ _digits[i] = 0;
+ _digitSequenceIds[i] = -1;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ _items[i]._currSequenceId = -1;
+ _items[i]._droppedSequenceId = 0;
+ _items[i]._x = 0;
+ _items[i]._y = 0;
+ _items[i]._collisionX = 0;
+ _items[i]._canCatch = false;
+ _items[i]._isCollision = false;
+ _items[i]._x2 = 0;
+ _items[i]._id = -1;
+ }
+}
+
+int Scene51::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ for (int i = 0; i < 6; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+ return 0xD4;
+}
+
+void Scene51::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene51::clearItem(Scene51Item *item) {
+ item->_currSequenceId = 0;
+ item->_droppedSequenceId = 0;
+ item->_x = 0;
+ item->_y = 0;
+ item->_x2 = 0;
+ item->_collisionX = 0;
+ item->_canCatch = false;
+}
+
+void Scene51::dropNextItem() {
+ if (_vm->_timers[0])
+ return;
+
+ int index = 0;
+ while (index < 6 && _items[index]._currSequenceId)
+ ++index;
+
+ if (index == 6)
+ return;
+
+ switch (_nextDropItemKind) {
+ case 0:
+ if (_vm->getRandom(10) != 0 || _itemsCtr2 >= 2) {
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 1:
+ if (_vm->getRandom(8) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) == 0) {
+ if (_itemInsertDirection)
+ _itemInsertX -= 70;
+ else
+ _itemInsertX += 70;
+ }
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 2:
+ if (_vm->getRandom(6) != 0 || _itemsCtr2 >= 2) {
+ _items[index]._currSequenceId = 0xBD;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 3:
+ case 4:
+ if (_itemsCtr == 0)
+ _itemsCtr1 = 3;
+ _items[index]._currSequenceId = 0xC0;
+ break;
+
+ case 5:
+ case 6:
+ if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ case 7:
+ if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(5) == 0) {
+ if (_itemInsertDirection)
+ _itemInsertX -= 40;
+ else
+ _itemInsertX += 40;
+ }
+ if (_vm->getRandom(9) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+
+ default:
+ if (_vm->getRandom(4) != 0 || _itemsCtr2 >= 2) {
+ if (_vm->getRandom(9) != 0)
+ _items[index]._currSequenceId = 0xBD;
+ else
+ _items[index]._currSequenceId = 0xC0;
+ } else {
+ --_itemsCtr1;
+ _items[index]._currSequenceId = 0xBA;
+ ++_itemsCtr2;
+ }
+ break;
+ }
+
+ if (_itemInsertDirection) {
+ _itemInsertX -= 73;
+ if (_itemInsertX < 129) {
+ _itemInsertX += 146;
+ _itemInsertDirection = 0;
+ }
+ } else {
+ _itemInsertX += 73;
+ if (_itemInsertX > 685) {
+ _itemInsertX -= 146;
+ _itemInsertDirection = 1;
+ }
+ }
+
+ if (_itemInsertX > 685)
+ _itemInsertX = 685;
+
+ if (_itemInsertX < 129)
+ _itemInsertX = 129;
+
+ if (_items[index]._currSequenceId == 0xBA) {
+ _items[index]._x2 = _vm->getRandom(350) + 200;
+ _items[index]._x = _items[index]._x2 - 362;
+ _items[index]._y = 15;
+ _items[index]._id = 249 - index;
+ } else {
+ _items[index]._collisionX = _itemInsertX;
+ _items[index]._x = _items[index]._collisionX - 395;
+ if (_items[index]._currSequenceId == 0xC0)
+ _items[index]._x -= 65;
+ _items[index]._id = index + 250;
+ _items[index]._canCatch = true;
+ }
+
+ _vm->_gameSys->setAnimation(_items[index]._currSequenceId, _items[index]._id, index + 1);
+ _vm->_gameSys->insertSequence(_items[index]._currSequenceId, _items[index]._id, 0, 0,
+ kSeqNone, 0, _items[index]._x, _items[index]._y);
+
+ _vm->_timers[0] = _dropSpeedTicks;
+
+ if (_nextDropItemKind >= 3)
+ _vm->_timers[0] = 20;
+
+ if (_nextDropItemKind >= 5)
+ _vm->_timers[0] = 5;
+
+ if (_nextDropItemKind == 8)
+ _vm->_timers[0] = 4;
+
+ ++_itemsCtr;
+}
+
+void Scene51::updateItemAnimations() {
+ for (int i = 0; i < 6; ++i) {
+ if (_vm->_gameSys->getAnimationStatus(i + 1) == 2)
+ updateItemAnimation(&_items[i], i);
+ }
+}
+
+int Scene51::checkCollision(int sequenceId) {
+ if (!isJumping(sequenceId))
+ return false;
+
+ bool jumpingLeft = false, jumpingRight = false;
+ int v8 = 0, v4 = 0;
+ int result = 0;
+
+ bool checkFl = false;
+ for (int i = 0; i < 6; i++)
+ checkFl |= _items[i]._isCollision;
+
+ if (!checkFl)
+ return false;
+
+ if (isJumpingRight(sequenceId)) {
+ v8 = getPosRight(sequenceId);
+ v4 = getPosRight(sequenceId + 1);
+ jumpingRight = true;
+ } else if (isJumpingLeft(sequenceId)) {
+ v4 = getPosLeft(sequenceId - 1) + 33;
+ v8 = getPosLeft(sequenceId) + 33;
+ jumpingLeft = true;
+ }
+
+ if (jumpingRight || jumpingLeft) {
+ int v5 = 0;
+ int i;
+ for (i = 0; i < 6; ++i) {
+ if (_items[i]._isCollision) {
+ if (jumpingRight && _items[i]._x2 > v8 && _items[i]._x2 < v4) {
+ v5 = v8 - 359;
+ if (v5 == 0)
+ v5 = 1;
+ _platypusNextSequenceId = 0xB6;
+ break;
+ } else if (jumpingLeft && _items[i]._x2 < v4 && _items[i]._x2 > v8) {
+ v5 = v8 - 344;
+ if (v5 == 0)
+ v5 = 1;
+ _platypusNextSequenceId = 0xB7;
+ break;
+ }
+ }
+ }
+ if (v5) {
+ _vm->_gameSys->setAnimation(0xBC, _items[i]._id, i + 1);
+ _vm->_gameSys->insertSequence(0xBC, _items[i]._id, _items[i]._currSequenceId, _items[i]._id, kSeqSyncWait, 0, _items[i]._x, 15);
+ _items[i]._isCollision = false;
+ _items[i]._currSequenceId = 0xBC;
+ --_itemsCtr2;
+ }
+ result = v5;
+ }
+
+ return result;
+}
+
+void Scene51::updateItemAnimation(Scene51Item *item, int index) {
+
+ switch (item->_currSequenceId) {
+ case 0xBD:
+ case 0xC0:
+ case 0xC1:
+ // Falling coin and banknote
+ if (!itemIsCaught(item)) {
+ if (_dropLoseCash) {
+ if (item->_currSequenceId == 0xBD)
+ _cashAmount -= 2;
+ else
+ _cashAmount -= 25;
+ if (_cashAmount < 0)
+ _cashAmount = 0;
+ updateCash(_cashAmount);
+ }
+ item->_droppedSequenceId = item->_currSequenceId + 1;
+ if (item->_currSequenceId != 0xC0) {
+ item->_canCatch = false;
+ _dropLoseCash = true;
+ _itemsCtr = 0;
+ _vm->_timers[0] = 10;
+ }
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ } else {
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ _vm->playSound(0xDA, false);
+ if (incCashAmount(item->_currSequenceId) == 1995) {
+ winMinigame();
+ _vm->_sceneDone = true;
+ } else {
+ clearItem(item);
+ ++_itemsCaughtCtr;
+ if (_itemsCaughtCtr == 5)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 8)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 11)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr == 14)
+ --_dropSpeedTicks;
+ if (_itemsCaughtCtr >= 15 && _dropSpeedTicks > 4)
+ --_dropSpeedTicks;
+ if (_itemsCtr1 <= _itemsCaughtCtr) {
+ ++_nextDropItemKind;
+ _dropSpeedTicks = 10;
+ _itemsCtr = 0;
+ _itemsCtr1 = 20;
+ _dropLoseCash = false;
+ _itemsCaughtCtr = 0;
+ removeCollidedItems();
+ }
+ }
+ }
+ break;
+
+ case 0xBE:
+ // Fallen coin
+ item->_droppedSequenceId = item->_currSequenceId + 1;
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+
+ case 0xBF:
+ case 0xC2:
+ // Bouncing coin and banknote
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ clearItem(item);
+ break;
+
+ case 0xBA:
+ // Falling banana peel
+ item->_droppedSequenceId = 0xBB;
+ item->_y = 15;
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+
+ case 0xBB:
+ item->_isCollision = true;
+ item->_droppedSequenceId = 0;
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ break;
+
+ case 0xBC:
+ _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true);
+ _vm->_gameSys->setAnimation(0, 0, index + 1);
+ clearItem(item);
+ break;
+
+ default:
+ if (item->_droppedSequenceId) {
+ _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1);
+ _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y);
+ item->_currSequenceId = item->_droppedSequenceId;
+ item->_y = 0;
+ }
+ break;
+ }
+}
+
+void Scene51::removeCollidedItems() {
+ for (int i = 0; i < 6; ++i) {
+ if (_items[i]._isCollision) {
+ _vm->_gameSys->removeSequence(_items[i]._currSequenceId, _items[i]._id, true);
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+ clearItem(&_items[i]);
+ }
+ }
+ _itemsCtr2 = 0;
+}
+
+int Scene51::itemIsCaught(Scene51Item *item) {
+ if (!item->_canCatch)
+ return 0;
+
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ int v4 = getPosRight(_platypusJumpSequenceId) + 97;
+ if (item->_collisionX < v4 && v4 - item->_collisionX < 56)
+ return 1;
+ } else {
+ int v2 = getPosLeft(_platypusJumpSequenceId);
+ if (item->_collisionX > v2 && item->_collisionX - v2 < 56)
+ return 1;
+ }
+
+ if (item->_currSequenceId == 0xC1) {
+ int v3 = item->_collisionX + 100;
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ if (ABS(getPosRight(_platypusJumpSequenceId) + 46 - v3) < 56)
+ return 1;
+ } else if (ABS(getPosLeft(_platypusJumpSequenceId) + 46 - v3) < 56) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+bool Scene51::isJumpingRight(int sequenceId) {
+ return sequenceId >= 0x76 && sequenceId <= 0x95;
+}
+
+bool Scene51::isJumpingLeft(int sequenceId) {
+ return sequenceId >= 0x96 && sequenceId <= 0xB5;
+}
+
+bool Scene51::isJumping(int sequenceId) {
+ return sequenceId >= 0x76 && sequenceId <= 0xB5;
+}
+
+void Scene51::waitForAnim(int animationIndex) {
+ while (_vm->_gameSys->getAnimationStatus(animationIndex) != 2 && _vm->_gameDone) {
+ updateItemAnimations();
+ _vm->gameUpdateTick();
+ }
+}
+
+int Scene51::getPosRight(int sequenceId) {
+ static const int kRightPosTbl[] = {
+ 131, 159, 178, 195, 203, 219, 238, 254,
+ 246, 274, 293, 310, 318, 334, 353, 369,
+ 362, 390, 409, 426, 434, 450, 469, 485,
+ 477, 505, 524, 541, 549, 565, 584, 600
+ };
+
+ if (sequenceId >= 118 && sequenceId <= 149)
+ return kRightPosTbl[sequenceId - 118];
+ return -1;
+}
+
+int Scene51::getPosLeft(int sequenceId) {
+ static const int kLeftPosTbl[] = {
+ 580, 566, 550, 536, 526, 504, 488, 469,
+ 460, 446, 430, 416, 406, 384, 368, 349,
+ 342, 328, 312, 298, 288, 266, 250, 231,
+ 220, 206, 190, 176, 166, 144, 128, 109
+ };
+
+ if (sequenceId >= 150 && sequenceId <= 181)
+ return kLeftPosTbl[sequenceId - 150];
+ return -1;
+}
+
+void Scene51::playIntroAnim() {
+ int soundCtr = 0;
+
+ _platypusSequenceId = 0x76;
+ _platypusNextSequenceId = 0x76;
+
+ for (int i = 0; i < 6; ++i)
+ clearItem(&_items[i]);
+
+ _items[0]._currSequenceId = 0xBA;
+ _items[0]._x2 = 320;
+ _items[0]._x = -42;
+ _items[0]._y = 15;
+ _items[0]._id = 249;
+ _items[0]._isCollision = true;
+
+ _vm->_gameSys->insertSequence(_platypusSequenceId, 256, 0, 0, kSeqNone, 0, -179, 0);
+ _vm->_gameSys->insertSequence(0xBA, 249, 0, 0, kSeqNone, 0, _items[0]._x, _items[0]._y);
+ _vm->_gameSys->setAnimation(0xBA, 249, 1);
+ _vm->_gameSys->setAnimation(_platypusSequenceId, 256, 0);
+
+ while (_platypusSequenceId < 0x80) {
+ waitForAnim(0);
+ ++_platypusNextSequenceId;
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, -179, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+
+ _platypusNextSequenceId = 0x75;
+
+ while (_platypusSequenceId != 0x84) {
+ waitForAnim(0);
+ ++_platypusNextSequenceId;
+ int oldSequenceId = _platypusNextSequenceId;
+ int v0 = checkCollision(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, v0, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (v0) {
+ _platypusNextSequenceId = oldSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ waitForAnim(0);
+}
+
+void Scene51::updateGuyAnimation() {
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _guyNextSequenceId = 0xC3;
+ break;
+ case 1:
+ _guyNextSequenceId = 0xC4;
+ break;
+ case 2:
+ _guyNextSequenceId = 0xC5;
+ break;
+ case 3:
+ _guyNextSequenceId = 0xC6;
+ break;
+ case 4:
+ _guyNextSequenceId = 0xC7;
+ break;
+ }
+
+ _vm->_gameSys->insertSequence(_guyNextSequenceId, 39, _guySequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _guySequenceId = _guyNextSequenceId;
+ _guyNextSequenceId = -1;
+ }
+}
+
+int Scene51::incCashAmount(int sequenceId) {
+ switch (sequenceId) {
+ case 0xBD:
+ _cashAmount += 10;
+ break;
+ case 0xC0:
+ case 0xC1:
+ _cashAmount += 100;
+ break;
+ case 0xB6:
+ case 0xB7:
+ _cashAmount -= 10 * _vm->getRandom(5) + 50;
+ if (_cashAmount < 0)
+ _cashAmount = 0;
+ break;
+ }
+ if (_cashAmount > 1995)
+ _cashAmount = 1995;
+ updateCash(_cashAmount);
+ return _cashAmount;
+}
+
+void Scene51::winMinigame() {
+ updateCash(1995);
+ _vm->playSound(0xDA, false);
+ _vm->delayTicksA(1, 5);
+ _vm->_newSceneNum = 48;
+ _vm->invRemove(kItemBanana);
+}
+
+void Scene51::playCashAppearAnim() {
+ _vm->_gameSys->setAnimation(0xC8, 252, 0);
+ _vm->_gameSys->insertSequence(0xC8, 252, 0, 0, kSeqNone, 0, -20, -20);
+
+ while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+}
+
+void Scene51::updateCash(int amount) {
+ drawDigit(amount / 1000, 0);
+ drawDigit(amount / 100 % 10, 1);
+ drawDigit(amount / 10 % 10, 2);
+ drawDigit(amount % 10, 3);
+}
+
+void Scene51::drawDigit(int digit, int position) {
+ if (digit != _digits[position]) {
+ _vm->_gameSys->insertSequence(kDigitSequenceIds[digit], 253 + position,
+ _digitSequenceIds[position], 253 + position,
+ kSeqSyncWait, 0, kDigitPositions[position] - 20, -20);
+ _digitSequenceIds[position] = kDigitSequenceIds[digit];
+ _digits[position] = digit;
+ }
+}
+
+void Scene51::initCashDisplay() {
+ for (int position = 0; position < 4; ++position) {
+ _digits[position] = 0;
+ _digitSequenceIds[position] = kDigitSequenceIds[0];
+ _vm->_gameSys->insertSequence(kDigitSequenceIds[0], 253 + position, 0, 0, kSeqNone, 0, kDigitPositions[position] - 20, -20);
+ }
+ _cashAmount = 0;
+}
+
+void Scene51::run() {
+ int soundCtr = 0;
+ bool isIdle = true;
+
+ _itemsCtr = 0;
+ _vm->_newSceneNum = _vm->_prevSceneNum;
+ _cashAmount = 0;
+ _platypusJumpSequenceId = 0x84;
+ _vm->endSceneInit();
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+
+ _guySequenceId = 0xC3;
+ _guyNextSequenceId = -1;
+
+ _vm->_gameSys->insertSequence(0xC3, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+
+ playCashAppearAnim();
+ initCashDisplay();
+ playIntroAnim();
+
+ _platypusNextSequenceId = 0x74;
+ _vm->_gameSys->setAnimation(0x74, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+
+ _itemInsertDirection = 0;
+ _itemInsertX = 685;
+ _dropSpeedTicks = 10;
+ _nextDropItemKind = 0;
+
+ for (int i = 0; i < 6; ++i)
+ clearItem(&_items[i]);
+
+ _itemInsertX = _vm->getRandom(556) + 129;
+ _vm->_timers[0] = 15;
+
+ _itemsCaughtCtr = 0;
+ _dropLoseCash = false;
+ _itemsCtr1 = 20;
+
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+
+ bool isCollision = false;
+ bool startWalk = true;
+
+ while (!_vm->_sceneDone) {
+ if (clearKeyStatus())
+ _vm->_sceneDone = true;
+
+ _vm->gameUpdateTick();
+
+ updateGuyAnimation();
+ dropNextItem();
+ updateItemAnimations();
+
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB8, 256, 0);
+ _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0);
+ _platypusSequenceId = 0xB8;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0x95)
+ _platypusNextSequenceId = 0x95;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB9, 256, 0);
+ _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0);
+ _platypusSequenceId = 0xB9;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0xB5)
+ _platypusNextSequenceId = 0xB5;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ isIdle = false;
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT) && _platypusNextSequenceId != 0x96 && !_vm->_gameDone) {
+ if (_platypusNextSequenceId == 0xB6)
+ _platypusNextSequenceId = 0x76;
+ updateItemAnimations();
+ if (startWalk) {
+ _platypusNextSequenceId = 0x86;
+ startWalk = false;
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(0) == 2) {
+ int collisionX = checkCollision(_platypusNextSequenceId);
+ if (collisionX)
+ incCashAmount(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (collisionX) {
+ isCollision = true;
+ ++_platypusJumpSequenceId;
+ _platypusNextSequenceId = _platypusJumpSequenceId;
+ } else {
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ ++_platypusNextSequenceId;
+ if (!isCollision) {
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB8, 256, 0);
+ _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0);
+ _platypusSequenceId = 0xB8;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0x95)
+ _platypusNextSequenceId = 0x95;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ } else {
+ _platypusNextSequenceId = 150 - (_platypusJumpSequenceId - 150);
+ }
+ isCollision = false;
+ isIdle = false;
+ }
+ _vm->gameUpdateTick();
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_LEFT) && _platypusNextSequenceId != 0xB6 && !_vm->_gameDone) {
+ updateItemAnimations();
+ if (startWalk) {
+ _platypusNextSequenceId = 0xA5;
+ startWalk = false;
+ }
+
+ if (_vm->_gameSys->getAnimationStatus(0) == 2) {
+ int collisionX = checkCollision(_platypusNextSequenceId);
+ if (collisionX)
+ incCashAmount(_platypusNextSequenceId);
+ _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0);
+ _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0);
+ _platypusSequenceId = _platypusNextSequenceId;
+ if (collisionX) {
+ isCollision = true;
+ ++_platypusJumpSequenceId;
+ _platypusNextSequenceId = _platypusJumpSequenceId;
+ } else {
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ }
+ if (isJumpingLeft(_platypusJumpSequenceId)) {
+ ++_platypusNextSequenceId;
+ if (!isCollision) {
+ if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ waitForAnim(0);
+ _vm->_gameSys->setAnimation(0xB9, 256, 0);
+ _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0);
+ _platypusSequenceId = 0xB9;
+ waitForAnim(0);
+ _platypusNextSequenceId += 6;
+ if (_platypusNextSequenceId > 0xB5)
+ _platypusNextSequenceId = 0xB5;
+ _platypusJumpSequenceId = _platypusNextSequenceId;
+ } else {
+ ++soundCtr;
+ if (soundCtr % 4 == 0)
+ _vm->playSound(0xD6, false);
+ }
+ }
+ } else {
+ _platypusNextSequenceId = 182 - (_platypusJumpSequenceId - 118);
+ }
+ isCollision = false;
+ isIdle = false;
+ }
+ _vm->gameUpdateTick();
+ }
+
+ if (!isIdle && _vm->_gameSys->getAnimationStatus(0) == 2) {
+ if (isJumpingRight(_platypusJumpSequenceId)) {
+ _vm->_gameSys->setAnimation(0x74, 256, 0);
+ _vm->_gameSys->insertSequence(0x74, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0);
+ _platypusSequenceId = 0x74;
+ } else {
+ _vm->_gameSys->setAnimation(0x75, 256, 0);
+ _vm->_gameSys->insertSequence(0x75, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 341, 0);
+ _platypusSequenceId = 0x75;
+ }
+ waitForAnim(0);
+ isIdle = true;
+ }
+ }
+
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ for (int i = 0; i < 6; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i + 1);
+
+ _vm->showCursor();
+}
+
+/*****************************************************************************/
+
+Scene52::Scene52(GnapEngine *vm) : Scene(vm) {
+ _gameScore = 0;
+ _aliensInitialized = false;
+ _alienDirection = 0;
+ _soundToggle = false;
+ _arcadeScreenBottom = 0;
+ _shipsLeft = 0;
+ _shipPosX = 0;
+ _shipCannonPosX = 0;
+ _shipCannonPosY = 0;
+ _shipCannonFiring = false;
+ _shipCannonFired = false;
+ _shipCannonWidth = 0;
+ _shipCannonHeight = 0;
+ _shipCannonTopY = 0;
+ _shipMidX = 0;
+ _shipMidY = 0;
+ _shipFlag = false;
+ _alienSpeed = 0;
+ _alienWidth = 0;
+ _alienHeight = 0;
+ _alienLeftX = 0;
+ _alienTopY = 0;
+ _alienRowDownCtr = 0;
+ _alienWave = false;
+ _alienSingle = false;
+ _alienCounter = 0;
+ _bottomAlienFlag = false;
+ _aliensCount = 0;
+ _nextUfoSequenceId = -1;
+ _ufoSequenceId = -1;
+ _liveAlienRows = 0;
+}
+
+int Scene52::init() {
+ initAnims();
+ return 0x2B;
+}
+
+void Scene52::updateHotspots() {
+ _vm->_hotspotsCount = 0;
+}
+
+void Scene52::update() {
+ for (int rowNum = 0; rowNum < 7 && !_vm->_gameDone; ++rowNum) {
+ _vm->gameUpdateTick();
+ if (_vm->_gameSys->getAnimationStatus(_alienRowAnims[rowNum]) == 2) {
+ updateAlienRow(rowNum);
+ rowNum = 0;
+ }
+ }
+
+ if (_liveAlienRows == 0 && !_alienSingle) {
+ _alienWave = false;
+ _vm->playSound(0x30, false);
+ ++_alienCounter;
+ if (_alienCounter != 3) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[2] = 100;
+ _alienRowDownCtr = 0;
+ _alienSingle = true;
+ }
+ }
+
+ if (_alienSingle && !_vm->_timers[0]) {
+ initAliens();
+ _alienSingle = false;
+ _vm->_timers[2] = 5;
+ _alienWave = true;
+ }
+
+ if ((_alienRowDownCtr || _liveAlienRows == 0) && !_alienSingle) {
+ moveDownAlienRow();
+ _alienRowDownCtr = 0;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_UP) || _vm->isKeyStatus1(Common::KEYCODE_SPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ if (!_aliensCount)
+ fireShipCannon(_shipPosX);
+ }
+
+ if (_shipCannonFiring)
+ updateShipCannon();
+
+ fireAlienCannon();
+ updateAlienCannons();
+
+ if (_aliensCount == 1) {
+ _alienWave = false;
+ _vm->_timers[3] = 20;
+ _vm->_timers[2] = 100;
+ ++_aliensCount;
+ }
+
+ if (_aliensCount && !_vm->_timers[3]) {
+ updateAliens();
+ loseShip();
+ if (_shipsLeft != 0) {
+ _vm->_timers[3] = 40;
+ while (_vm->_timers[3] && !_vm->_gameDone) {
+ updateAlienCannons();
+ if (_shipCannonFiring)
+ updateShipCannon();
+ _vm->gameUpdateTick();
+ }
+ initAliens();
+ _shipPosX = (800 - _shipMidX) / 2;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ _vm->_timers[2] = 5;
+ _alienWave = true;
+ } else {
+ _vm->_sceneDone = true;
+ }
+ }
+
+ _nextUfoSequenceId = 34;
+ if (_ufoSequenceId != 34)
+ _shipFlag = true;
+
+ if (_shipFlag) {
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ }
+ _shipFlag = false;
+ }
+
+ if (_alienWave && !_vm->_timers[0]) {
+ playSound();
+ int delay = CLIP(_alienSpeed, 2, 10);
+ _vm->_timers[0] = delay;
+ }
+}
+
+void Scene52::initShipCannon(int bottomY) {
+ _shipCannonFired = false;
+ _shipCannonWidth = MAX(_vm->_gameSys->getSpriteWidthById(14), _vm->_gameSys->getSpriteWidthById(16));
+ _shipCannonHeight = MAX(_vm->_gameSys->getSpriteHeightById(14), _vm->_gameSys->getSpriteHeightById(16));
+ _shipCannonTopY = bottomY - _shipCannonHeight;
+ _shipCannonFiring = false;
+}
+
+void Scene52::initAlienCannons() {
+ for (int i = 0; i < 3; ++i) {
+ _alienCannonIds[i] = 0;
+ _alienCannonFired[i] = 0;
+ }
+ _alienCannonSequenceIds[0] = 30;
+ _alienCannonSequenceIds[1] = 31;
+ _alienCannonSequenceIds[2] = 32;
+}
+
+void Scene52::fireShipCannon(int posX) {
+ if (_vm->_timers[1])
+ return;
+
+ int cannonNum = getFreeShipCannon();
+ if (cannonNum != -1) {
+ _shipCannonPosX = _shipMidX / 2 + posX - _shipCannonWidth / 2;
+ _shipCannonPosY = _shipCannonTopY;
+ _vm->_gameSys->setAnimation(0x23, cannonNum + 256, cannonNum + 8);
+ _vm->_gameSys->insertSequence(0x23, cannonNum + 256, 0, 0, kSeqNone, 0, _shipCannonPosX, _shipCannonPosY);
+ _vm->playSound(0x2D, false);
+ if (shipCannonHitShield(cannonNum)) {
+ _vm->_gameSys->setAnimation(0, 0, cannonNum + 8);
+ _vm->_gameSys->removeSequence(0x23, cannonNum + 256, true);
+ } else {
+ _shipCannonFired = true;
+ _shipCannonPosY -= 13;
+ _shipCannonFiring = true;
+ }
+ _vm->_timers[1] = 5;
+ }
+}
+
+void Scene52::fireAlienCannon() {
+ if (_vm->_timers[2])
+ return;
+
+ int cannonNum = getFreeAlienCannon();
+ if (cannonNum != -1) {
+ int alienX1 = _alienLeftX + _alienRowXOfs[0];
+ int alienX2 = _alienLeftX + _alienRowXOfs[0] + 5 * _alienWidth - (_alienWidth / 2 - 15);
+ _alienCannonPosX[cannonNum] = _vm->getRandom(alienX2 - alienX1) + alienX1;
+ _alienCannonPosY[cannonNum] = 104;
+ _alienCannonFired[cannonNum] = 1;
+ _vm->_gameSys->setAnimation(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, cannonNum + 9);
+ _vm->_gameSys->insertSequence(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, 0, 0,
+ kSeqNone, 0, _alienCannonPosX[cannonNum], _alienCannonPosY[cannonNum]);
+ _alienCannonPosY[cannonNum] -= 13;
+ _vm->_timers[2] = 5;
+ }
+}
+
+int Scene52::getFreeShipCannon() {
+ if (!_shipCannonFired)
+ return 0;
+ return -1;
+}
+
+int Scene52::getFreeAlienCannon() {
+ for (int i = 0; i < 3; ++i)
+ if (!_alienCannonFired[i])
+ return i;
+ return -1;
+}
+
+void Scene52::updateShipCannon() {
+ if (_shipCannonFired && _vm->_gameSys->getAnimationStatus(8) == 2) {
+ _shipCannonPosY -= 13;
+ if (_shipCannonPosY - 13 >= 135) {
+ if (updateHitAlien()) {
+ _vm->_gameSys->setAnimation(0, 0, 8);
+ _vm->_gameSys->removeSequence(35, 256, true);
+ _shipCannonFired = false;
+ drawScore(_gameScore);
+ } else {
+ _vm->_gameSys->setAnimation(35, 256, 8);
+ _vm->_gameSys->insertSequence(35, 256, 35, 256, kSeqSyncWait, 0, _shipCannonPosX, _shipCannonPosY);
+ _shipCannonPosY -= 13;
+ }
+ } else {
+ _vm->_gameSys->setAnimation(0, 0, 8);
+ _vm->_gameSys->removeSequence(35, 256, true);
+ _shipCannonFired = false;
+ }
+ }
+}
+
+void Scene52::updateAlienCannons() {
+ for (int i = 0; i < 3; ++i) {
+ if (_alienCannonFired[i] && _vm->_gameSys->getAnimationStatus(i + 9) == 2) {
+ _alienCannonPosY[i] += 13;
+ if (_shipCannonHeight + _alienCannonPosY[i] + 13 <= 550) {
+ if (alienCannonHitShip(i)) {
+ _vm->_gameSys->setAnimation(0, 0, i + 9);
+ _alienCannonFired[i] = 0;
+ shipExplode();
+ } else if (alienCannonHitShield(i)) {
+ _alienCannonFired[i] = 0;
+ } else {
+ _vm->_gameSys->insertSequence(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, 0, 0,
+ kSeqNone, 0, _alienCannonPosX[i], _alienCannonPosY[i]);
+ _vm->_gameSys->setAnimation(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, i + 9);
+ _alienCannonIds[i] = 1 - _alienCannonIds[i];
+ _alienCannonPosY[i] += 13;
+ }
+ } else {
+ _vm->_gameSys->setAnimation(0, 0, i + 9);
+ _alienCannonFired[i] = 0;
+ }
+ }
+ }
+}
+
+void Scene52::initAliens() {
+ if (!_aliensInitialized) {
+ initAlienSize();
+ _aliensInitialized = true;
+ }
+
+ _liveAlienRows = 0;
+ _alienSpeed = 0;
+ _bottomAlienFlag = false;
+ _aliensCount = 0;
+ _alienSingle = false;
+ _alienRowDownCtr = 0;
+
+ initShields();
+
+ _alienRowKind[0] = -1;
+ _alienRowKind[1] = -1;
+ _alienRowKind[2] = -1;
+ _alienRowKind[3] = -1;
+ _alienRowKind[4] = _vm->getRandom(2) != 0 ? 24 : 27;
+ _alienRowKind[5] = _vm->getRandom(2) != 0 ? 25 : 28;
+ _alienRowKind[6] = _vm->getRandom(2) != 0 ? 26 : 29;
+
+ for (int i = 0; i < 7; ++i) {
+ _alienRowAnims[i] = i;
+ _alienRowXOfs[i] = 0;
+ initAlienRowKind(i, _alienRowKind[i]);
+ insertAlienRow(i);
+ }
+}
+
+void Scene52::initAlienRowKind(int rowNum, int alienKind) {
+ for (int i = 0; i < 5; ++i)
+ _items[rowNum][i] = alienKind;
+}
+
+void Scene52::insertAlienRow(int rowNum) {
+ if (_alienRowKind[rowNum] >= 0) {
+ insertAlienRowAliens(rowNum);
+ _alienRowIds[rowNum] = 256;
+ _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]);
+ ++_liveAlienRows;
+ }
+}
+
+void Scene52::insertAlienRowAliens(int rowNum) {
+ int xOffs = _alienLeftX;
+ int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10;
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0) {
+ _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, 0, 0, kSeqNone, 0, xOffs, yOffs);
+ ++_alienSpeed;
+ }
+ xOffs += _alienWidth;
+ }
+}
+
+void Scene52::updateAlienRow(int rowNum) {
+ if (_alienRowKind[rowNum] != -1 && !checkAlienRow(rowNum)) {
+ updateAlienRowXOfs();
+ _alienRowIds[rowNum] = -1;
+ int xOffs = _alienLeftX + _alienRowXOfs[rowNum];
+ int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10;
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0) {
+ _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, _items[rowNum][i], i + 256, kSeqSyncWait, 0, xOffs, yOffs);
+ if (_alienRowIds[rowNum] == -1)
+ _alienRowIds[rowNum] = i + 256;
+ } else if (_items[rowNum][i] == -2) {
+ _vm->_gameSys->removeSequence(_alienRowKind[rowNum], i + 256, true);
+ _items[rowNum][i] = -1;
+ --_alienSpeed;
+ }
+ xOffs += _alienWidth;
+ }
+ if (_alienRowIds[rowNum] == -1) {
+ _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]);
+ // MessageBoxA(0, "No live aliens!", "Error 3:", 0x30u);
+ } else {
+ _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]);
+ }
+ if (rowNum == 1) {
+ for (int j = 0; j < 3; ++j) {
+ if (_shieldSpriteIds[j] != -1) {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[j], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[j] = -1;
+ }
+ }
+ }
+ if (rowNum == 0 && _bottomAlienFlag)
+ shipExplode();
+ }
+}
+
+void Scene52::moveDownAlienRow() {
+ int v2[5], v3, v1, v0, v4;
+
+ for (int i = 0; i < 5; ++i)
+ v2[i] = _items[0][i];
+
+ v3 = _alienRowIds[0];
+ v1 = _alienRowAnims[0];
+ v0 = _alienRowKind[0];
+ v4 = _alienRowXOfs[0];
+
+ for (int j = 0; j < 7; ++j) {
+ for (int i = 0; i < 5; ++i)
+ _items[j][i] = _items[j + 1][i];
+ _alienRowIds[j] = _alienRowIds[j + 1];
+ _alienRowAnims[j] = _alienRowAnims[j + 1];
+ _alienRowKind[j] = _alienRowKind[j + 1];
+ _alienRowXOfs[j] = _alienRowXOfs[j + 1];
+ }
+
+ for (int i = 0; i < 5; ++i)
+ _items[6][i] = v2[i];
+
+ _alienRowIds[6] = v3;
+ _alienRowAnims[6] = v1;
+ _alienRowKind[6] = v0;
+ _alienRowXOfs[6] = v4;
+
+ updateAlien(6);
+ initAlienRowKind(6, _alienRowKind[6]);
+ insertAlienRow(6);
+
+ _bottomAlienFlag = _alienRowKind[0] > -1;
+}
+
+int Scene52::updateHitAlien() {
+ int result = 0, rowNum, ya;
+
+ int y = _shipCannonTopY - _shipCannonPosY;
+
+ if (y == 26) {
+ rowNum = 1;
+ ya = _shipCannonPosY + 26;
+ } else {
+ if (y % 52)
+ return 0;
+ rowNum = y / 52 + 1;
+ ya = _shipCannonPosY;
+ }
+
+ if (rowNum < 7) {
+ int hitAlienNum = getHitAlienNum(rowNum);
+ if (hitAlienNum != -1 && _items[rowNum][hitAlienNum] >= 0) {
+ _gameScore = ((_items[rowNum][hitAlienNum] - 24) % 3 + _gameScore + 1) % 1000;
+ _items[rowNum][hitAlienNum] = -2;
+ _vm->playSound(0x2C, false);
+ _vm->_gameSys->insertSequence(0x21, 266, 0, 0,
+ kSeqNone, 0, _alienLeftX + hitAlienNum * _alienWidth + _alienRowXOfs[rowNum] - 10, ya - _alienHeight);
+ result = 1;
+ }
+ }
+
+ return result;
+}
+
+int Scene52::getHitAlienNum(int rowNum) {
+ int result = -1;
+
+ int v3 = _alienLeftX + _alienRowXOfs[rowNum];
+
+ if (_shipCannonPosX >= v3) {
+ int v8 = _alienWidth / 2 - 15;
+ if (v3 + 5 * _alienWidth - v8 >= _shipCannonPosX) {
+ int v4 = v3 + _alienWidth;
+ if (_shipCannonPosX >= v4 - v8) {
+ int v5 = v4 + _alienWidth;
+ if (_shipCannonPosX >= v5 - v8) {
+ int v6 = v5 + _alienWidth;
+ if (_shipCannonPosX >= v6 - v8) {
+ int v7 = v6 + _alienWidth;
+ if (_shipCannonPosX >= v7 - v8) {
+ if (_shipCannonPosX >= v7 + _alienWidth - v8)
+ result = -1;
+ else
+ result = 4;
+ } else {
+ result = 3;
+ }
+ } else {
+ result = 2;
+ }
+ } else {
+ result = 1;
+ }
+ } else {
+ result = 0;
+ }
+ } else {
+ result = -1;
+ }
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+int Scene52::alienCannonHitShip(int cannonNum) {
+ int result = 0;
+
+ if (_aliensCount) {
+ result = 0;
+ } else {
+ int cannonY = _alienCannonPosY[cannonNum] - 13;
+ if (_arcadeScreenBottom <= cannonY) {
+ if (_shipMidY + _arcadeScreenBottom > cannonY) {
+ if (_alienCannonPosX[cannonNum] >= _shipPosX)
+ result = _alienCannonPosX[cannonNum] < _shipMidX + _shipPosX;
+ else
+ result = 0;
+ } else {
+ result = 0;
+ }
+ } else {
+ result = 0;
+ }
+ }
+ return result;
+}
+
+int Scene52::alienCannonHitShield(int cannonNum) {
+ int result = 0;
+
+ int v3 = _alienCannonPosY[cannonNum] + 39;
+ if (_arcadeScreenBottom - 44 > v3)
+ return 0;
+
+ if (_arcadeScreenBottom <= v3)
+ return 0;
+
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[0])
+ return 0;
+
+ if (_alienCannonPosX[cannonNum] > _shieldPosX[2] + 33)
+ return 0;
+
+ int shieldNum = -1;
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[0] + 33)
+ shieldNum = 0;
+
+ if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1])
+ return 0;
+
+ if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1] + 33)
+ shieldNum = 1;
+
+ if (shieldNum < 0) {
+ if (_alienCannonPosX[cannonNum] < _shieldPosX[2])
+ return 0;
+ shieldNum = 2;
+ }
+
+ if (_shieldSpriteIds[shieldNum] == -1) {
+ result = 0;
+ } else {
+ ++_shieldSpriteIds[shieldNum];
+ if (_shieldSpriteIds[shieldNum] <= 21) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]);
+ } else {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[shieldNum] = -1;
+ }
+ _vm->_gameSys->setAnimation(0, 0, cannonNum + 9);
+ _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _alienCannonPosX[cannonNum] - 18, _arcadeScreenBottom - 44);
+ _vm->playSound(0x2C, false);
+ result = 1;
+ }
+
+ return result;
+}
+
+bool Scene52::shipCannonHitShield(int cannonNum) {
+ bool result = false;
+
+ if (_shipCannonPosX < _shieldPosX[0])
+ return result;
+
+ if (_shipCannonPosX > _shieldPosX[2] + 33)
+ return result;
+
+ int shieldNum = -1;
+ if (_shipCannonPosX < _shieldPosX[0] + 33)
+ shieldNum = 0;
+
+ if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1])
+ return result;
+
+ if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1] + 33)
+ shieldNum = 1;
+
+ if (shieldNum < 0) {
+ if (_shipCannonPosX < _shieldPosX[2])
+ return result;
+ shieldNum = 2;
+ }
+
+ if (_shieldSpriteIds[shieldNum] == -1) {
+ result = false;
+ } else {
+ ++_shieldSpriteIds[shieldNum];
+ if (_shieldSpriteIds[shieldNum] <= 21) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]);
+ } else {
+ _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0);
+ _shieldSpriteIds[shieldNum] = -1;
+ }
+ _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _shipCannonPosX - 18, _arcadeScreenBottom - 44);
+ _vm->playSound(0x2C, false);
+ result = true;
+ }
+
+ return result;
+}
+
+bool Scene52::shipCannonHitAlien() {
+ bool result = false;
+
+ if (_aliensCount || checkAlienRow(0))
+ return false;
+
+ int alienNextX = _alienLeftX + _alienRowXOfs[0];
+ if (_shipMidX + _shipPosX >= alienNextX) {
+ int startX = _alienWidth / 2 - 15;
+ if (alienNextX + 5 * _alienWidth - startX >= _shipPosX) {
+ int alienNextDeltaX = alienNextX + _alienWidth;
+ if (_items[0][0] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][1] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][2] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ if (_items[0][3] <= -1 || alienNextDeltaX - startX <= _shipPosX) {
+ alienNextDeltaX += _alienWidth;
+ result = _items[0][4] > -1 && alienNextDeltaX - startX > _shipPosX;
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = true;
+ }
+ } else {
+ result = false;
+ }
+ } else {
+ result = false;
+ }
+
+ return result;
+}
+
+void Scene52::shipExplode() {
+ if (!_aliensCount) {
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ _vm->_gameSys->removeSequence(_ufoSequenceId, 256, true);
+ _vm->playSound(0x2C, false);
+ _vm->_gameSys->insertSequence(0x21, 266, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+ _aliensCount = 1;
+ _vm->playSound(0x31, false);
+ }
+}
+
+bool Scene52::checkAlienRow(int rowNum) {
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0)
+ return false;
+ }
+
+ bool found = false;
+ for (int j = 0; j < 5; ++j)
+ if (_items[rowNum][j] == -2) {
+ _vm->_gameSys->removeSequence(_alienRowKind[rowNum], j + 256, true);
+ _items[rowNum][j] = -1;
+ --_alienSpeed;
+ found = true;
+ }
+
+ if (found) {
+ _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]);
+ --_liveAlienRows;
+ }
+
+ if (_liveAlienRows < 0)
+ _liveAlienRows = 0;
+
+ return true;
+}
+
+void Scene52::updateAlienRowXOfs() {
+ int amount = 2 * (3 - _liveAlienRows) + 1;
+
+ if (_alienSpeed == 2)
+ amount *= 4;
+ else if (_alienSpeed == 1)
+ amount *= 10;
+
+ if (_alienDirection) {
+ for (int i = 0; i < 7; ++i) {
+ _alienRowXOfs[i] -= amount;
+ if (_alienRowXOfs[i] <= -100) {
+ _alienRowXOfs[i] = -100;
+ _alienDirection = 0;
+ ++_alienRowDownCtr;
+ }
+ }
+ } else {
+ for (int j = 0; j < 7; ++j) {
+ _alienRowXOfs[j] += amount;
+ if (_alienRowXOfs[j] >= 100) {
+ _alienRowXOfs[j] = 100;
+ _alienDirection = 1;
+ ++_alienRowDownCtr;
+ }
+ }
+ }
+}
+
+void Scene52::initAlienSize() {
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(0);
+ if (_vm->_gameSys->getSpriteWidthById(1) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(1);
+ if (_vm->_gameSys->getSpriteWidthById(4) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(4);
+ if (_vm->_gameSys->getSpriteWidthById(5) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(5);
+ if (_vm->_gameSys->getSpriteWidthById(12) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(12);
+ if (_vm->_gameSys->getSpriteWidthById(13) > _alienWidth)
+ _alienWidth = _vm->_gameSys->getSpriteWidthById(13);
+
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(0);
+ if (_vm->_gameSys->getSpriteHeightById(1) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(1);
+ if (_vm->_gameSys->getSpriteHeightById(4) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(4);
+ if (_vm->_gameSys->getSpriteHeightById(5) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(5);
+ if (_vm->_gameSys->getSpriteHeightById(12) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(12);
+ if (_vm->_gameSys->getSpriteHeightById(13) > _alienHeight)
+ _alienHeight = _vm->_gameSys->getSpriteHeightById(13);
+
+ _alienTopY = _shipCannonTopY + 52;
+ _alienLeftX = (800 - 5 * _alienWidth) / 2;
+}
+
+void Scene52::playSound() {
+ if (_soundToggle) {
+ _vm->playSound(0x2F, false);
+ _soundToggle = false;
+ } else {
+ _vm->playSound(0x2E, false);
+ _soundToggle = true;
+ }
+}
+
+void Scene52::updateAliens() {
+ for (int i = 0; i < 7; ++i)
+ updateAlien(i);
+}
+
+void Scene52::updateAlien(int rowNum) {
+ if (_alienRowKind[rowNum] >= 0 && !checkAlienRow(rowNum)) {
+ for (int i = 0; i < 5; ++i) {
+ if (_items[rowNum][i] >= 0)
+ _items[rowNum][i] = -2;
+ }
+ checkAlienRow(rowNum);
+ }
+}
+
+void Scene52::loseShip() {
+ --_shipsLeft;
+ if (_shipsLeft == 2) {
+ _vm->_gameSys->fillSurface(nullptr, 120, 140, _shipMidX, _shipMidY, 0, 0, 0);
+ } else if (_shipsLeft == 1) {
+ _vm->_gameSys->fillSurface(nullptr, 120, 185, _shipMidX, _shipMidY, 0, 0, 0);
+ }
+}
+
+void Scene52::initShields() {
+ for (int i = 0; i < 3; ++i) {
+ _vm->_gameSys->drawSpriteToBackground(_shieldPosX[i], _arcadeScreenBottom - 44, 17);
+ _shieldSpriteIds[i] = 17;
+ }
+}
+
+void Scene52::initAnims() {
+ for (int i = 0; i < 7; ++i)
+ _vm->_gameSys->setAnimation(0, 0, i);
+ _vm->_gameSys->setAnimation(0, 0, 7);
+ for (int j = 0; j < 1; ++j)
+ _vm->_gameSys->setAnimation(0, 0, j + 8);
+ for (int k = 0; k < 3; ++k)
+ _vm->_gameSys->setAnimation(0, 0, k + 9);
+}
+
+void Scene52::drawScore(int score) {
+ char str[4];
+ sprintf(str, "%03d", score);
+ _vm->_gameSys->fillSurface(nullptr, 420, 80, 48, 30, 0, 0, 0);
+ _vm->_gameSys->drawTextToSurface(nullptr, 420, 80, 255, 255, 255, str);
+}
+
+void Scene52::run() {
+ _vm->_timers[1] = 0;
+
+ _vm->hideCursor();
+
+ _gameScore = 0;
+ _vm->_gameSys->drawTextToSurface(nullptr, 300, 80, 255, 255, 255, "SCORE");
+ _vm->_gameSys->drawTextToSurface(nullptr, 468, 80, 255, 255, 255, "0");
+
+ drawScore(0);
+
+ _shipMidX = 33;
+ _shipMidY = _vm->_gameSys->getSpriteHeightById(15);
+ _shipPosX = (800 - _shipMidX) / 2;
+ _arcadeScreenBottom = 496;
+ int arcadeScreenRight = 595 - _shipMidX;
+ int arcadeScreenLeft = 210;
+ _shipsLeft = 3;
+ _alienCounter = 0;
+
+ _shieldPosX[0] = 247;
+ _shieldPosX[1] = 387;
+ _shieldPosX[2] = 525;
+
+ for (int i = 0; i < 3; ++i)
+ _shieldSpriteIds[i] = -1;
+
+ _vm->_gameSys->drawSpriteToBackground(120, 140, 0xF);
+ _vm->_gameSys->drawSpriteToBackground(120, 185, 0xF);
+
+ initShipCannon(_arcadeScreenBottom);
+ initAlienCannons();
+ initAliens();
+
+ _nextUfoSequenceId = 0x22;
+ _vm->_gameSys->setAnimation(0x22, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom);
+
+ _ufoSequenceId = _nextUfoSequenceId;
+
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+
+ _vm->_timers[2] = 5;
+ _shipFlag = false;
+
+ _vm->_timers[0] = 10;
+ _alienWave = true;
+
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT)) {
+ update();
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ if (_shipPosX < arcadeScreenRight) {
+ _shipPosX += 15;
+ if (_shipPosX > arcadeScreenRight)
+ _shipPosX = arcadeScreenRight;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ if (_bottomAlienFlag && shipCannonHitAlien())
+ shipExplode();
+ }
+ break;
+ }
+ }
+
+ while (_vm->isKeyStatus2(Common::KEYCODE_LEFT)) {
+ update();
+ if (_vm->_gameSys->getAnimationStatus(7) == 2) {
+ if (_shipPosX > arcadeScreenLeft) {
+ _shipPosX -= 15;
+ if (_shipPosX < arcadeScreenLeft)
+ _shipPosX = arcadeScreenLeft;
+ _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7);
+ _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom);
+ _ufoSequenceId = _nextUfoSequenceId;
+ if (_bottomAlienFlag && shipCannonHitAlien())
+ shipExplode();
+ }
+ break;
+ }
+ }
+
+ update();
+
+ if (clearKeyStatus()) {
+ _alienWave = false;
+ _vm->_gameSys->waitForUpdate();
+ initAnims();
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->_sceneDone = true;
+ }
+ }
+ _vm->_gameSys->waitForUpdate();
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/arcade.h b/engines/gnap/scenes/arcade.h
new file mode 100644
index 0000000000..ab519ee00b
--- /dev/null
+++ b/engines/gnap/scenes/arcade.h
@@ -0,0 +1,288 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_ARCADE_H
+#define GNAP_ARCADE_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+class CutScene;
+
+struct Scene49Obstacle {
+ int _currSequenceId;
+ int _closerSequenceId;
+ int _passedSequenceId;
+ int _splashSequenceId;
+ int _collisionSequenceId;
+ int _prevId;
+ int _currId;
+ int _laneNum;
+};
+
+struct ObstacleDef {
+ int _sequenceId;
+ int _ticks;
+};
+
+class Scene49: public Scene {
+public:
+ Scene49(GnapEngine *vm);
+ ~Scene49() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _scoreBarPos;
+ int _scoreLevel;
+ bool _scoreBarFlash;
+ int _obstacleIndex;
+ Scene49Obstacle _obstacles[5];
+ int _truckSequenceId;
+ int _truckId;
+ int _truckLaneNum;
+
+ void checkObstacles();
+ void updateObstacle(int id);
+ void increaseScore(int amount);
+ void decreaseScore(int amount);
+ void refreshScoreBar();
+ void clearObstacle(int index);
+};
+
+/*****************************************************************************/
+
+class Scene50: public Scene {
+public:
+ Scene50(GnapEngine *vm);
+ ~Scene50() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _fightDone;
+ int _timesPlayed;
+ int _timesPlayedModifier;
+ int _attackCounter;
+ int _roundNum;
+ int _timeRemaining;
+ int _leftTongueRoundsWon;
+ int _rightTongueRoundsWon;
+ int _leftTongueEnergyBarPos;
+ int _rightTongueEnergyBarPos;
+ int _leftTongueSequenceId;
+ int _leftTongueId;
+ int _leftTongueNextSequenceId;
+ int _leftTongueNextId;
+ int _leftTongueNextIdCtr;
+ int _rightTongueSequenceId;
+ int _rightTongueId;
+ int _rightTongueNextSequenceId;
+ int _rightTongueNextId;
+ int _rightTongueNextIdCtr;
+ int _leftTongueEnergy;
+ int _rightTongueEnergy;
+
+ bool tongueWinsRound(int tongueNum);
+ void playWinAnim(int tongueNum, bool fightOver);
+ void delayTicks();
+ void initRound();
+ bool updateCountdown();
+ void drawCountdown(int value);
+ void playTonguesIdle();
+ void playRoundAnim(int roundNum);
+ bool updateEnergyBars(int newLeftBarPos, int newRightBarPos);
+ void waitForAnim(int animationIndex);
+ int checkInput();
+ int getRightTongueAction();
+ int getRightTongueActionTicks();
+ int getLeftTongueNextId();
+ int getRightTongueNextId();
+ void playWinBadgeAnim(int tongueNum);
+};
+
+/*****************************************************************************/
+
+struct Scene51Item {
+ int _currSequenceId;
+ int _droppedSequenceId;
+ int _x, _y;
+ int _collisionX;
+ bool _canCatch;
+ bool _isCollision;
+ int _x2;
+ int _id;
+};
+
+class Scene51: public Scene {
+public:
+ Scene51(GnapEngine *vm);
+ ~Scene51() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _dropLoseCash;
+
+ int _cashAmount;
+ int _digits[4];
+ int _digitSequenceIds[4];
+ int _guySequenceId;
+ int _guyNextSequenceId;
+ int _itemsCaughtCtr;
+ int _dropSpeedTicks;
+ int _nextDropItemKind;
+ int _itemInsertX;
+ int _itemInsertDirection;
+ int _platypusSequenceId;
+ int _platypusNextSequenceId;
+ int _platypusJumpSequenceId;
+ int _itemsCtr;
+ int _itemsCtr1;
+ int _itemsCtr2;
+
+ Scene51Item _items[6];
+
+ void clearItem(Scene51Item *item);
+ void dropNextItem();
+ void updateItemAnimations();
+ int checkCollision(int sequenceId);
+ void updateItemAnimation(Scene51Item *item, int index);
+ void removeCollidedItems();
+ int itemIsCaught(Scene51Item *item);
+ bool isJumpingRight(int sequenceId);
+ bool isJumpingLeft(int sequenceId);
+ bool isJumping(int sequenceId);
+ void waitForAnim(int animationIndex);
+ int getPosRight(int sequenceId);
+ int getPosLeft(int sequenceId);
+ void playIntroAnim();
+ void updateGuyAnimation();
+ int incCashAmount(int sequenceId);
+ void winMinigame();
+ void playCashAppearAnim();
+ void updateCash(int amount);
+ void drawDigit(int digit, int position);
+ void initCashDisplay();
+};
+
+/*****************************************************************************/
+
+class Scene52: public Scene {
+public:
+ Scene52(GnapEngine *vm);
+ ~Scene52() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _liveAlienRows;
+ int _gameScore;
+ bool _soundToggle;
+ int _arcadeScreenBottom;
+ int _shipsLeft;
+ int _shieldSpriteIds[3];
+ int _shieldPosX[3];
+ int _shipPosX;
+ int _shipCannonPosX, _shipCannonPosY;
+ bool _shipCannonFiring;
+ bool _shipCannonFired;
+ int _shipCannonWidth, _shipCannonHeight;
+ int _shipCannonTopY;
+ int _shipMidX, _shipMidY;
+ bool _shipFlag;
+ bool _aliensInitialized;
+ int _alienSpeed, _alienDirection;
+ int _alienWidth, _alienHeight;
+ int _alienLeftX, _alienTopY;
+ int _alienRowDownCtr;
+ int _alienRowKind[8];
+ int _alienRowAnims[8];
+ int _alienRowIds[8];
+ int _alienRowXOfs[8];
+ int _alienCannonFired[3];
+ int _alienCannonPosX[3];
+ int _alienCannonPosY[3];
+ int _alienCannonSequenceIds[3];
+ int _alienCannonIds[3];
+ bool _alienWave, _alienSingle;
+ int _alienCounter;
+ bool _bottomAlienFlag;
+ int _aliensCount;
+ int _items[8][5];
+ int _nextUfoSequenceId, _ufoSequenceId;
+
+ void update();
+ void initShipCannon(int bottomY);
+ void initAlienCannons();
+ void fireShipCannon(int posX);
+ void fireAlienCannon();
+ int getFreeShipCannon();
+ int getFreeAlienCannon();
+ void updateShipCannon();
+ void updateAlienCannons();
+ void initAliens();
+ void initAlienRowKind(int rowNum, int alienKind);
+ void insertAlienRow(int rowNum);
+ void insertAlienRowAliens(int rowNum);
+ void updateAlienRow(int rowNum);
+ void moveDownAlienRow();
+ int updateHitAlien();
+ int getHitAlienNum(int rowNum);
+ int alienCannonHitShip(int cannonNum);
+ int alienCannonHitShield(int cannonNum);
+ bool shipCannonHitShield(int cannonNum);
+ bool shipCannonHitAlien();
+ void shipExplode();
+ bool checkAlienRow(int rowNum);
+ void updateAlienRowXOfs();
+ void initAlienSize();
+ void playSound();
+ void updateAliens();
+ void updateAlien(int rowNum);
+ void loseShip();
+ void initShields();
+ void initAnims();
+ void drawScore(int score);
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_ARCADE_H
diff --git a/engines/gnap/scenes/group0.cpp b/engines/gnap/scenes/group0.cpp
new file mode 100644
index 0000000000..e76fd9bbd2
--- /dev/null
+++ b/engines/gnap/scenes/group0.cpp
@@ -0,0 +1,3570 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/character.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group0.h"
+
+namespace Gnap {
+
+Scene01::Scene01(GnapEngine *vm) : Scene(vm) {
+ _pigsIdCtr = 0;
+ _smokeIdCtr = 0;
+ _spaceshipSurface = nullptr;
+}
+
+Scene01::~Scene01() {
+ delete _spaceshipSurface;
+}
+
+int Scene01::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ return 0x88;
+}
+
+void Scene01::updateHotspots() {
+ _vm->setHotspot(kHS01Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS01ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6);
+ _vm->setHotspot(kHS01Mud, 138, 282, 204, 318, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5);
+ _vm->setHotspot(kHS01Pigs, 408, 234, 578, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 4);
+ _vm->setHotspot(kHS01Spaceship, 0, 200, 94, 292, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6);
+ _vm->setHotspot(kHS01WalkArea1, 0, 0, 162, 426);
+ _vm->setHotspot(kHS01WalkArea2, 162, 0, 237, 396);
+ _vm->setHotspot(kHS01WalkArea3, 237, 0, 319, 363);
+ _vm->setHotspot(kHS01WalkArea4, 520, 0, 800, 404);
+ _vm->setHotspot(kHS01WalkArea5, 300, 447, 800, 600);
+ _vm->setHotspot(kHS01WalkArea6, 678, 0, 800, 404);
+ _vm->setHotspot(kHS01WalkArea7, 0, 0, 520, 351);
+ _vm->setHotspot(kHS01WalkArea8, 0, 546, 300, 600);
+ _vm->setDeviceHotspot(kHS01Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS01Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFMudTaken))
+ _vm->_hotspots[kHS01Mud]._flags = SF_WALKABLE | SF_DISABLED;
+ _vm->_hotspotsCount = 14;
+}
+
+void Scene01::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(5);
+
+ gameSys.setAnimation(134, 20, 4);
+ gameSys.insertSequence(134, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.setAnimation(0x7F, 40, 2);
+ gameSys.insertSequence(0x7F, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ if (!_vm->isFlag(kGFMudTaken))
+ gameSys.insertSequence(129, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 2) {
+ gnap.initPos(11, 6, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107B9, 1);
+ } else {
+ gnap.initPos(1, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 3, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS01Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS01Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Spaceship:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 0, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS01LookSpaceship;
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Mud:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 3)) | 0x10000, 1);
+ gnap._actionStatus = kAS01TakeMud;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01Pigs:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 7, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01LookPigs;
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01UsePigs;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(7, 2)) | 0x10000, 1);
+ gnap._actionStatus = kAS01LookPigs;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS01ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS01LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 2;
+ }
+ break;
+
+ case kHS01WalkArea1:
+ case kHS01WalkArea2:
+ case kHS01WalkArea3:
+ case kHS01WalkArea4:
+ case kHS01WalkArea5:
+ case kHS01WalkArea6:
+ case kHS01WalkArea7:
+ case kHS01WalkArea8:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (_vm->_timers[4] == 0) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(1) == 0)
+ gameSys.insertSequence(0x84, 180, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x83, 180, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene01::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS01LookSpaceship:
+ _spaceshipSurface = gameSys.createSurface(47);
+ gameSys.insertSpriteDrawItem(_spaceshipSurface, 0, 0, 255);
+ gameSys.setAnimation(133, 256, 0);
+ gameSys.insertSequence(133, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = kAS01LookSpaceshipDone;
+ break;
+
+ case kAS01LookSpaceshipDone:
+ gameSys.removeSequence(133, 256, true);
+ gameSys.removeSpriteDrawItem(_spaceshipSurface, 255);
+ _vm->deleteSurface(&_spaceshipSurface);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+
+ case kAS01TakeMud:
+ gnap.playPullOutDevice(Common::Point(2, 3));
+ gnap.playUseDevice();
+ gameSys.insertSequence(128, 40, 129, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(128, 40, 3);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01LookPigs:
+ _vm->playSound(0x8A, false);
+ _vm->playSound(0x8B, false);
+ _vm->playSound(0x8C, false);
+ gnap._actionStatus = -1;
+ break;
+
+ case kAS01UsePigs:
+ gnap.playPullOutDevice(Common::Point(7, 2));
+ gnap.playUseDevice();
+ gameSys.insertSequence(135, 39, 0, 0, kSeqNone, 25, _vm->getRandom(140) - 40, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 3);
+ _vm->invAdd(kItemMud);
+ _vm->setGrabCursorSprite(kItemMud);
+ _vm->setFlag(kGFMudTaken);
+ updateHotspots();
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ _smokeIdCtr = (_smokeIdCtr + 1) % 2;
+ gameSys.setAnimation(0x86, _smokeIdCtr + 20, 4);
+ gameSys.insertSequence(0x86, _smokeIdCtr + 20,
+ 0x86, (_smokeIdCtr + 1) % 2 + 20,
+ kSeqSyncWait, 0, 0, 0);
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ _pigsIdCtr = (_pigsIdCtr + 1) % 2;
+ gameSys.setAnimation(0x7F, _pigsIdCtr + 40, 2);
+ gameSys.insertSequence(0x7F, _pigsIdCtr + 40,
+ 0x7F, (_pigsIdCtr + 1) % 2 + 40,
+ kSeqSyncWait, 0, 0, 0);
+ }
+}
+
+/*****************************************************************************/
+
+Scene02::Scene02(GnapEngine *vm) : Scene(vm) {
+ _truckGrillCtr = 0;
+ _nextChickenSequenceId = 0;
+ _currChickenSequenceId = 0;
+ _gnapTruckSequenceId = 0;
+}
+
+int Scene02::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ return _vm->isFlag(kGFTruckKeysUsed) ? 0x15A : 0x15B;
+}
+
+void Scene02::updateHotspots() {
+ _vm->setHotspot(kHS02Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS02Platypus]._flags |= SF_DISABLED;
+ _vm->setHotspot(kHS02Chicken, 606, 455, 702, 568, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS02Truck1, 385, 258, 464, 304, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 5);
+ _vm->setHotspot(kHS02Truck2, 316, 224, 390, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 6);
+ _vm->setHotspot(kHS02TruckGrill, 156, 318, 246, 390, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 7);
+ _vm->setHotspot(kHS02ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 5);
+ _vm->setHotspot(kHS02ExitBarn, 610, 0, 800, 164, SF_EXIT_U_CURSOR, 10, 5);
+ _vm->setHotspot(kHS02ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS02ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS02WalkArea1, 92, 140, 304, 430, SF_NONE, 3, 1);
+ _vm->setHotspot(kHS02WalkArea2, 0, 0, 800, 380);
+ _vm->setHotspot(kHS02WalkArea3, 0, 0, 386, 445);
+ _vm->setHotspot(kHS02WalkArea4, 386, 0, 509, 410);
+ _vm->setDeviceHotspot(kHS02Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 14;
+}
+
+void Scene02::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(6);
+
+ _currChickenSequenceId = 0x14B;
+ gameSys.setAnimation(0x14B, 179, 2);
+ gameSys.insertSequence(0x14B, 179, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextChickenSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ _vm->queueInsertDeviceIcon();
+
+ switch (_vm->_prevSceneNum) {
+ case 3:
+ gnap.initPos(11, 6, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1);
+ break;
+ case 4:
+ gnap.initPos(_vm->_hotspotsWalkPos[6].x, _vm->_hotspotsWalkPos[6].y, kDirBottomLeft);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(_vm->_hotspotsWalkPos[6].x + 1, _vm->_hotspotsWalkPos[6].y, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107B9, 1);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(8, 6), 1, 0x107C2, 1);
+ updateHotspots();
+ gameSys.waitForUpdate();
+ break;
+ case 47:
+ _vm->clearFlag(kGFUnk25);
+ gnap.initPos(5, 6, kDirBottomLeft);
+ plat.initPos(6, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ break;
+ case 49:
+ gnap.initPos(5, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(6, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ default:
+ gnap.initPos(-1, 6, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(-1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 6, 7, 6, 8, 6);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS02Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS02Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig) {
+ gnap._idleFacing = kDirUpRight;
+ Common::Point destPos = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1);
+ gnap.walkTo(destPos, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02UseTwigWithChicken;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), 9, 8);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(9, 8));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS02GrabChicken;
+ else
+ gnap._actionStatus = -1;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02TalkChicken;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02Truck1:
+ case kHS02Truck2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemKeys) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) {
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemKeys);
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ gnap._actionStatus = kAS02UseTruckGas;
+ else
+ gnap._actionStatus = kAS02UseTruckNoGas;
+ }
+ } else if (_vm->_grabCursorSpriteIndex == kItemGas) {
+ _vm->_hotspots[kHS02WalkArea4]._flags |= SF_WALKABLE;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1))
+ gnap._actionStatus = kAS02UseGasWithTruck;
+ _vm->_hotspots[kHS02WalkArea4]._flags &= ~SF_WALKABLE;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 2));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) {
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ gnap._actionStatus = kAS02UseTruckGas;
+ else
+ gnap._actionStatus = kAS02UseTruckNoGas;
+ }
+ } else {
+ gnap._idleFacing = kDirIdleRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1))
+ gnap._actionStatus = kAS02UseTruckNoKeys;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02TruckGrill:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS02GrabTruckGrill;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS02ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[6], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), -1, 0x107C1, 1);
+ updateHotspots();
+ _vm->_newSceneNum = 4;
+ }
+ break;
+
+ case kHS02ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[7] + Common::Point(1, 0), -1, 0x107C1, 1);
+ updateHotspots();
+ _vm->_newSceneNum = 5;
+ }
+ break;
+
+ case kHS02ExitCreek:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[8], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 3;
+ }
+ break;
+
+ case kHS02ExitPigpen:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[9], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS02LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[9], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 1;
+ }
+ break;
+
+ case kHS02WalkArea1:
+ case kHS02WalkArea2:
+ case kHS02WalkArea3:
+ case kHS02WalkArea4:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x156, 256, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x154, 256, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != 7 && gnap._actionStatus != 8) {
+ if (_vm->getRandom(6) != 0) {
+ _nextChickenSequenceId = 0x14B;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ } else {
+ _nextChickenSequenceId = 0x14D;
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene02::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS02UseTruckNoKeys:
+ gameSys.insertSequence(0x14E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x14E, gnap._id, 0);
+ gnap._sequenceId = 0x14E;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS02UseTruckNoKeysDone;
+ break;
+ case kAS02UseGasWithTruck:
+ gameSys.insertSequence(0x151, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x151, gnap._id, 0);
+ gnap._sequenceId = 0x151;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemGas);
+ _vm->setGrabCursorSprite(-1);
+ _vm->setFlag(kGFTruckFilledWithGas);
+ gnap._actionStatus = kAS02UseGasWithTruckDone;
+ break;
+ case kAS02UseTruckGas:
+ _vm->_timers[5] = 9999;
+ _vm->_timers[4] = 9999;
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.waitForUpdate();
+ _vm->setFlag(kGFTruckKeysUsed);
+ gnap._sequenceId = 0x14F;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemKeys);
+ _vm->setGrabCursorSprite(-1);
+ }
+ _vm->_newSceneNum = 47;
+ _vm->_sceneDone = true;
+ break;
+ case kAS02UseTruckNoGas:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->_timers[4] = 250;
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.waitForUpdate();
+ _vm->setFlag(kGFTruckKeysUsed);
+ gnap._sequenceId = 0x14F;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemKeys);
+ _vm->setGrabCursorSprite(-1);
+ }
+ _vm->_newSceneNum = 47;
+ _vm->_sceneDone = true;
+ _vm->setFlag(kGFUnk25);
+ break;
+ case kAS02GrabTruckGrill:
+ switch (_truckGrillCtr) {
+ case 0:
+ _gnapTruckSequenceId = 0x158;
+ break;
+ case 1:
+ _gnapTruckSequenceId = 0x159;
+ break;
+ case 2:
+ _gnapTruckSequenceId = 0x157;
+ break;
+ }
+ _truckGrillCtr = (_truckGrillCtr + 1) % 3;
+ gameSys.insertSequence(_gnapTruckSequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_gnapTruckSequenceId, gnap._id, 0);
+ gnap._sequenceId = _gnapTruckSequenceId;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS02LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS02TalkChicken:
+ _nextChickenSequenceId = 0x14C;
+ break;
+ case kAS02GrabChicken:
+ _nextChickenSequenceId = 0x150;
+ _vm->_timers[2] = 100;
+ break;
+ case kAS02GrabChickenDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 0x150, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ _currChickenSequenceId = 0x14B;
+ gameSys.setAnimation(0x14B, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_timers[5] = 30;
+ break;
+ case kAS02UseTwigWithChicken:
+ gnap.playShowItem(5, 0, 0);
+ gameSys.insertSequence(0x155, 179, _currChickenSequenceId, 179, kSeqSyncExists, 0, 0, 0);
+ _currChickenSequenceId = 0x155;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ case kAS02UseTruckNoKeysDone:
+ case kAS02UseGasWithTruckDone:
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextChickenSequenceId == 0x150) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 0);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(_currChickenSequenceId, 179, true);
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+ gnap._actionStatus = kAS02GrabChickenDone;
+ _vm->_timers[5] = 500;
+ } else if (_nextChickenSequenceId == 0x14C) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene03::Scene03(GnapEngine *vm) : Scene(vm) {
+ _nextPlatSequenceId = -1;
+ _platypusScared = false;
+ _platypusHypnotized = false;
+ _nextFrogSequenceId = -1;
+ _currFrogSequenceId = -1;
+}
+
+int Scene03::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 5);
+ return 0x1CC;
+}
+
+void Scene03::updateHotspots() {
+ _vm->setHotspot(kHS03Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS03Grass, 646, 408, 722, 458, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6);
+ _vm->setHotspot(kHS03ExitTruck, 218, 64, 371, 224, SF_EXIT_U_CURSOR | SF_WALKABLE, 4, 4);
+ _vm->setHotspot(kHS03Creek, 187, 499, 319, 587, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS03TrappedPlatypus, 450, 256, 661, 414, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 5);
+ _vm->setHotspot(kHS03WalkAreas1, 0, 500, 300, 600);
+ _vm->setHotspot(kHS03WalkAreas2, 300, 447, 800, 600);
+ _vm->setHotspot(kHS03PlatypusWalkArea, 235, 0, 800, 600);
+ _vm->setHotspot(kHS03WalkAreas3, 0, 0, 800, 354);
+ _vm->setDeviceHotspot(kHS03Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFGrassTaken))
+ _vm->_hotspots[kHS03Grass]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03TrappedPlatypus]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized)
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene03::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10925, true);
+ _vm->startSoundTimerC(7);
+
+ gameSys.insertSequence(0x1CA, 251, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x1CB, 251, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _platypusHypnotized = false;
+ gnap.initPos(3, 4, kDirBottomRight);
+
+ gameSys.insertSequence(0x1C6, 253, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currFrogSequenceId = 0x1C6;
+ _nextFrogSequenceId = -1;
+ gameSys.setAnimation(0x1C6, 253, 2);
+
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+
+ if (_vm->isFlag(kGFPlatypus)) {
+ plat.initPos(5, 4, kDirIdleLeft);
+ } else {
+ _vm->_timers[1] = _vm->getRandom(40) + 20;
+ gameSys.setAnimation(0x1C2, 99, 1);
+ gameSys.insertSequence(0x1C2, 99, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x1C2;
+ plat._sequenceDatNum = 0;
+ }
+
+ gameSys.insertSequence(0x1C4, 255, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFGrassTaken))
+ gameSys.insertSequence(0x1B2, 253, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ _vm->endSceneInit();
+
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(4, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(3, 6), -1, 0x107B9, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS03Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03Grass:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 6));
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(Common::Point(9, 6));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x1B3, 253, 0x1B2, 253, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1B3, 253, 5);
+ _vm->_hotspots[kHS03Grass]._flags |= SF_WALKABLE | SF_DISABLED;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS03LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[2], -1, 0x107C2, 1);
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 2;
+ else
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS03Creek:
+ if (gnap._actionStatus == -1) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 8));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[3] + Common::Point(1, 1)) | 0x10000, 1))
+ gnap._actionStatus = kAS03GrabCreek;
+ if (!_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03TrappedPlatypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus)) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_platypusHypnotized) {
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107B5, 1);
+ gnap._actionStatus = kAS03FreePlatypus;
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03GrabScaredPlatypus;
+ else
+ gnap._actionStatus = kAS03GrabPlatypus;
+ }
+ break;
+ case TALK_CURSOR:
+ if (_platypusHypnotized) {
+ gnap.playBrainPulsating(Common::Point(8, 4));
+ } else {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03HypnotizeScaredPlat;
+ else
+ gnap._actionStatus = kAS03HypnotizePlat;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS03Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS03WalkAreas1:
+ case kHS03WalkAreas2:
+ case kHS03WalkAreas3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS03PlatypusWalkArea:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107B5, 1);
+ if (_platypusScared)
+ gnap._actionStatus = kAS03GrabScaredPlatypus;
+ else
+ gnap._actionStatus = kAS03GrabPlatypus;
+ }
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10925))
+ _vm->playSound(0x10925, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[1] && !_platypusScared) {
+ _vm->_timers[1] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && !_vm->isFlag(kGFPlatypus) && !_platypusHypnotized)
+ _nextPlatSequenceId = 450;
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextFrogSequenceId == -1) {
+ if (_vm->getRandom(5) == 1)
+ _nextFrogSequenceId = 0x1C6;
+ else
+ _nextFrogSequenceId = 0x1C7;
+ }
+ }
+ if (!_vm->_timers[4]) {
+ // Update bird animation
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0)
+ gameSys.insertSequence(_vm->getRandom(2) != 0 ? 0x1C8 : 0x1C3, 253, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ gameSys.setAnimation(0x1C5, 253, 4);
+ gameSys.insertSequence(0x1C5, 253, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene03::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS03LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS03FreePlatypus:
+ _nextPlatSequenceId = 0x1BC;
+ break;
+ case kAS03FreePlatypusDone:
+ gnap._actionStatus = -1;
+ plat._pos = Common::Point(6, 6);
+ plat._idleFacing = kDirIdleRight;
+ plat._id = 120;
+ gameSys.insertSequence(0x107CA, plat._id, 0x1BC, 99,
+ kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.insertSequence(0x1B7, 99, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceDatNum = 1;
+ plat._sequenceId = 0x7CA;
+ _vm->setFlag(kGFPlatypus);
+ _nextPlatSequenceId = -1;
+ updateHotspots();
+ break;
+ case kAS03HypnotizePlat:
+ gnap.playBrainPulsating();
+ _vm->addFullScreenSprite(0x106, 255);
+ gameSys.setAnimation(0x1C9, 256, 1);
+ gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ gameSys.setAnimation(0x1BA, 99, 1);
+ gameSys.insertSequence(0x1BA, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x1BA;
+ gnap._actionStatus = -1;
+ _platypusHypnotized = true;
+ updateHotspots();
+ break;
+ case kAS03HypnotizeScaredPlat:
+ gnap.playBrainPulsating();
+ gameSys.insertSequence(0x1BF, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0);
+ gameSys.setAnimation(0x1BF, 99, 1);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->addFullScreenSprite(0x106, 255);
+ gameSys.setAnimation(0x1C9, 256, 1);
+ gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ gameSys.setAnimation(0x1BA, 99, 1);
+ gameSys.insertSequence(0x1BA, 99, 447, 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x1BA;
+ gnap._actionStatus = -1;
+ _platypusHypnotized = true;
+ updateHotspots();
+ break;
+ case kAS03GrabPlatypus:
+ _nextPlatSequenceId = 0x1BD;
+ _platypusHypnotized = false;
+ break;
+ case kAS03GrabScaredPlatypus:
+ _nextPlatSequenceId = 0x1C0;
+ _platypusHypnotized = false;
+ break;
+ case kAS03GrabCreek:
+ gameSys.insertSequence(0x1B4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1B4, gnap._id, 0);
+ gnap._sequenceId = 0x1B4;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS03GrabCreekDone;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ if (_nextPlatSequenceId == 0x1BD || _nextPlatSequenceId == 0x1C0) {
+ gameSys.setAnimation(0, 0, 1);
+ _platypusScared = true;
+ gameSys.insertSequence(0x1B5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextPlatSequenceId, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x1B5;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirIdleLeft;
+ plat._sequenceId = _nextPlatSequenceId;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(_nextPlatSequenceId, 99, 1);
+ _nextPlatSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextPlatSequenceId == 0x1BC) {
+ gnap._pos = Common::Point(3, 6);
+ gameSys.insertSequence(0x1B6, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1BC, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1BC, 99, 0);
+ gnap._id = 20 * gnap._pos.y;
+ gnap._sequenceId = 0x1B6;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirIdleLeft;
+ gnap._actionStatus = kAS03FreePlatypusDone;
+ _nextPlatSequenceId = -1;
+ } else if (_nextPlatSequenceId == 0x1C2 && !_platypusScared) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.insertSequence(0x1C2, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x1C2;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x1C2, 99, 1);
+ _nextPlatSequenceId = -1;
+ } else if (_nextPlatSequenceId == -1 && _platypusScared && !_platypusHypnotized) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0x1BE, 99, 1);
+ gameSys.insertSequence(0x1BE, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x1BE;
+ plat._sequenceDatNum = 0;
+ _nextPlatSequenceId = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextFrogSequenceId != -1) {
+ gameSys.setAnimation(_nextFrogSequenceId, 253, 2);
+ gameSys.insertSequence(_nextFrogSequenceId, 253, _currFrogSequenceId, 253, kSeqSyncWait, 0, 0, 0);
+ _currFrogSequenceId = _nextFrogSequenceId;
+ _nextFrogSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(5) == 2) {
+ gameSys.setAnimation(0, 0, 5);
+ _vm->invAdd(kItemGrass);
+ _vm->setGrabCursorSprite(kItemGrass);
+ _vm->setFlag(kGFGrassTaken);
+ updateHotspots();
+ }
+}
+
+/*****************************************************************************/
+
+Scene04::Scene04(GnapEngine *vm) : Scene(vm) {
+ _dogIdCtr = 0;
+ _triedWindow = false;
+ _nextDogSequenceId = -1;
+ _currDogSequenceId = -1;
+}
+
+int Scene04::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x214;
+}
+
+void Scene04::updateHotspots() {
+ _vm->setHotspot(kHS04Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS04Twig, 690, 394, 769, 452, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6);
+ _vm->setHotspot(kHS04Dog, 550, 442, 680, 552, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS04Axe, 574, 342, 680, 412, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS04Door, 300, 244, 386, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS04ExitTruck, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS04Window, 121, 295, 237, 342, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS04ExitBarn, 585, 154, 800, 276, SF_EXIT_U_CURSOR, 10, 8);
+ _vm->setHotspot(kHS04WalkArea1, 0, 0, 562, 461);
+ _vm->setHotspot(kHS04WalkArea2, 562, 0, 800, 500);
+ _vm->setDeviceHotspot(kHS04Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS04Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS04Twig]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant) || _vm->_cursorValue == 1)
+ _vm->_hotspots[kHS04Axe]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene04::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(4);
+
+ gameSys.insertSequence(0x210, 139 - _dogIdCtr, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currDogSequenceId = 0x210;
+ _nextDogSequenceId = -1;
+
+ gameSys.setAnimation(0x210, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ _vm->_timers[5] = _vm->getRandom(150) + 300;
+ _vm->_timers[7] = _vm->getRandom(150) + 200;
+ _vm->_timers[8] = _vm->getRandom(150) + 400;
+
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant) && _vm->_cursorValue == 4)
+ gameSys.insertSequence(0x212, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTwigTaken))
+ gameSys.insertSequence(0x1FE, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ _vm->_timers[3] = 300;
+ _vm->setGrabCursorSprite(kItemKeys);
+ gnap._pos = Common::Point(4, 7);
+ gnap._id = 140;
+ plat._pos = Common::Point(6, 7);
+ plat._id = 141;
+ gameSys.insertSequence(0x107B5, 140, 0, 0, kSeqNone, 0, 300 - gnap._gridX, 336 - gnap._gridY);
+ gameSys.insertSequence(0x20C, 141, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x208, 121, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x209, 121, 0x208, 121, kSeqSyncWait, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->invRemove(kItemDisguise);
+ _vm->invAdd(kItemKeys);
+ _vm->setFlag(kGFKeysTaken);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ plat._sequenceId = 0x20C;
+ plat._sequenceDatNum = 0;
+ plat._idleFacing = kDirBottomRight;
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gameSys.waitForUpdate();
+ } else {
+ gameSys.insertSequence(0x209, 121, 0, 0, kSeqNone, 0, 0, 0);
+ if (_vm->_prevSceneNum == 2) {
+ gnap.initPos(5, 11, kDirUpRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(6, 9), -1, 0x107BA, 1);
+ } else if (_vm->_prevSceneNum == 38) {
+ gnap.initPos(5, 7, kDirBottomRight);
+ plat.initPos(4, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(12, 9, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(12, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(9, 9), -1, 0x107BA, 1);
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 4, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS04Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS04Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ if (_vm->_cursorValue == 4)
+ gnap.kissPlatypus(0);
+ else
+ gnap.playMoan1(plat._pos);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Twig:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[1]);
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(_vm->_hotspotsWalkPos[1]);
+ gnap.playUseDevice(_vm->_hotspotsWalkPos[1]);
+ gameSys.insertSequence(0x1FD, 100, 510, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x1FD, 100, 2);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Axe:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 9, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(_vm->_hotspotsWalkPos[3]);
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS04GrabAxe;
+ _vm->setFlag(kGFPlatypusTalkingToAssistant);
+ updateHotspots();
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Dog:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 9, 7);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (gnap.walkTo(gnap._pos, 0, -1, 1)) {
+ gnap.playMoan2(_vm->_hotspotsWalkPos[2]);
+ _nextDogSequenceId = 0x20F;
+ }
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS04GrabDog;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(gnap._pos, 0, -1, 1)) {
+ gnap.playBrainPulsating(_vm->_hotspotsWalkPos[2]);
+ _nextDogSequenceId = 0x20E;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04Door:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 4, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->_cursorValue == 1) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS04OpenDoor;
+ _vm->_timers[5] = 300;
+ gnap._idleFacing = kDirUpLeft;
+ } else {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ _vm->_newSceneNum = 38;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[5], -1, 0x107C7, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 2;
+ else
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS04Window:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 3);
+ } else if (_vm->isFlag(kGFKeysTaken)) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, gnap.getSequenceId(kGSIdle, Common::Point(10, 2)) | 0x10000, 1)) {
+ if (_triedWindow) {
+ gnap._actionStatus = kAS04GetKeyAnother;
+ } else {
+ gnap._actionStatus = kAS04GetKeyFirst;
+ _triedWindow = true;
+ }
+ }
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[7]);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS04ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS04LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[8] + Common::Point(0, 1), -1, 0x107C1, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 5;
+ else
+ _vm->_newSceneNum = 35;
+ }
+ break;
+
+ case kHS04WalkArea1:
+ case kHS04WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence2();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(150) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0x20D, 79, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(150) + 200;
+ gameSys.insertSequence(0x1FC, 59, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ if (_nextDogSequenceId == -1)
+ _nextDogSequenceId = 0x210;
+ }
+ if (!_vm->_timers[8]) {
+ _vm->_timers[8] = _vm->getRandom(150) + 400;
+ gameSys.insertSequence(0x213, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene04::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS04LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS04OpenDoor:
+ gameSys.insertSequence(0x205, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x207, 121, 521, 121, kSeqSyncWait, 0, 0, 0);
+ gnap._pos = Common::Point(6, 7);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x205) - 1, 450 - gnap._gridX, 336 - gnap._gridY);
+ gameSys.setAnimation(0x107B5, gnap._id, 0);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._actionStatus = kAS04OpenDoorDone;
+ break;
+ case kAS04OpenDoorDone:
+ gameSys.insertSequence(0x209, 121, 0x207, 121, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GetKeyFirst:
+ gameSys.insertSequence(0x204, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x204, gnap._id, 0);
+ gnap._sequenceId = 0x204;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyFirst2;
+ break;
+ case kAS04GetKeyFirst2:
+ gameSys.insertSequence(0x206, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x20B, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x20B, 256, 0);
+ gnap._sequenceId = 0x206;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyFirstDone;
+ break;
+ case kAS04GetKeyFirstDone:
+ gameSys.requestRemoveSequence(0x1FF, 256);
+ gameSys.requestRemoveSequence(0x20B, 256);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._idleFacing = kDirBottomRight;
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GetKeyAnother:
+ gameSys.insertSequence(0x202, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x202, gnap._id, 0);
+ gnap._sequenceId = 0x202;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyAnother2;
+ break;
+ case kAS04GetKeyAnother2:
+ gameSys.insertSequence(0x203, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x20A, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x20A, 256, 0);
+ gnap._sequenceId = 0x203;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS04GetKeyAnotherDone;
+ break;
+ case kAS04GetKeyAnotherDone:
+ gameSys.removeSequence(0x1FF, 256, true);
+ gameSys.removeSequence(0x20A, 256, true);
+ gameSys.insertSequence(0x107B5, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gnap._idleFacing = kDirBottomRight;
+ gnap._actionStatus = -1;
+ break;
+ case kAS04GrabDog:
+ _nextDogSequenceId = 0x201;
+ break;
+ case kAS04GrabAxe:
+ gameSys.insertSequence(0x211, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.requestRemoveSequence(0x212, 100);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x211;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->invAdd(kItemTwig);
+ _vm->setGrabCursorSprite(kItemTwig);
+ _vm->setFlag(kGFTwigTaken);
+ updateHotspots();
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextDogSequenceId == 0x201) {
+ gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr,
+ _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _currDogSequenceId = 0x201;
+ gnap._sequenceId = 0x200;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ _vm->_timers[6] = _vm->getRandom(20) + 60;
+ _nextDogSequenceId = -1;
+ } else if (_nextDogSequenceId != -1) {
+ gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr,
+ _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3);
+ _dogIdCtr = (_dogIdCtr + 1) % 2;
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene05::Scene05(GnapEngine *vm) : Scene(vm) {
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+}
+
+int Scene05::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 3);
+ return _vm->isFlag(kGFBarnPadlockOpen) ? 0x151 : 0x150;
+}
+
+void Scene05::updateHotspots() {
+ _vm->setHotspot(kHS05Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS05Haystack, 236, 366, 372, 442, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS05Padlock, 386, 230, 626, 481, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS05Ladder, 108, 222, 207, 444, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS05ExitHouse, 0, 395, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS05Chicken, 612, 462, 722, 564, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS05WalkArea1, 104, 0, 421, 480);
+ _vm->setHotspot(kHS05WalkArea2, 422, 0, 800, 487);
+ _vm->setHotspot(kHS05WalkArea3, 0, 0, 104, 499);
+ _vm->setDeviceHotspot(kHS05Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS05Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ _vm->_hotspots[kHS05Padlock]._flags = SF_EXIT_U_CURSOR;
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene05::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(7);
+
+ _currChickenSequenceId = 0x142;
+ gameSys.setAnimation(0x142, 100, 3);
+ gameSys.insertSequence(0x142, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextChickenSequenceId = -1;
+
+ _vm->_timers[5] = _vm->getRandom(10) + 30;
+ _vm->_timers[6] = _vm->getRandom(150) + 300;
+
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ gameSys.insertSequence(0x14A, 141, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum != 6 && _vm->_prevSceneNum != 36) {
+ gnap.initPos(-1, 8, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(-1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(Common::Point(2, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 9), -1, 0x107B9, 1);
+ } else {
+ gnap.initPos(6, 8, kDirBottomRight);
+ if (_vm->isFlag(kGFPlatypus))
+ plat.initPos(7, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 12, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS05Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS05Platypus:
+ if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Haystack:
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(-2, 0), 4, 5);
+ } else if (_vm->isFlag(kGFNeedleTaken)) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(_vm->_hotspotsWalkPos[1] + Common::Point(0, -1));
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFPlatypus)) {
+ gnap.useDeviceOnPlatypus();
+ if (plat.walkTo(_vm->_hotspotsWalkPos[1], 1, 0x107C2, 1)) {
+ plat._actionStatus = kAS05PlatSearchHaystack;
+ plat._idleFacing = kDirIdleRight;
+ }
+ if (gnap._pos.x == 4 && (gnap._pos.y == 8 || gnap._pos.y == 7))
+ gnap.walkStep();
+ gnap.playIdle(plat._pos);
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig) {
+ gnap._idleFacing = kDirUpRight;
+ Common::Point checkPt = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1);
+ gnap.walkTo(checkPt, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05UseTwigWithChicken;
+ } else if (_vm->_grabCursorSpriteIndex >= 0)
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1), 9, 7);
+ else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(9, 7));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05GrabChicken;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05TalkChicken;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Ladder:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05GrabLadder;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05Padlock:
+ if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_isLeavingScene = true;
+ Common::Point destPt = _vm->_hotspotsWalkPos[2] + Common::Point(- 1, 1);
+ gnap.walkTo(destPt, 0, -1, 1);
+ gnap._actionStatus = kAS05EnterBarn;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 6;
+ else
+ _vm->_newSceneNum = 36;
+ } else if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemNeedle) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0,
+ gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1))
+ gnap._actionStatus = kAS05PickPadlock;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 7, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS05TryPickPadlock;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS05ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS05LeaveScene;
+ if (_vm->isFlag(kGFPlatypus))
+ plat.walkTo(_vm->_hotspotsWalkPos[4] + Common::Point(0, 1), -1, 0x107C7, 1);
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 4;
+ else
+ _vm->_newSceneNum = 37;
+ }
+ break;
+
+ case kHS05WalkArea1:
+ case kHS05WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS05WalkArea3:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (_vm->isFlag(kGFPlatypus))
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus != kAS05TalkChicken && _nextChickenSequenceId == -1) {
+ if (_vm->getRandom(4) != 0)
+ _nextChickenSequenceId = 0x142;
+ else
+ _nextChickenSequenceId = 0x143;
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(150) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0x149, 39, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene05::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS05LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05TryPickPadlock:
+ gameSys.insertSequence(0x148, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x148;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05PickPadlock:
+ gameSys.setAnimation(0x147, gnap._id, 0);
+ gameSys.insertSequence(0x147, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x147;
+ gnap._sequenceDatNum = 0;
+ _vm->setFlag(kGFBarnPadlockOpen);
+ _vm->setFlag(kGFSceneFlag1);
+ _vm->setGrabCursorSprite(-1);
+ _vm->_newSceneNum = 6;
+ _vm->_timers[2] = 100;
+ _vm->invRemove(kItemNeedle);
+ gnap._actionStatus = kAS05LeaveScene;
+ break;
+ case kAS05TalkChicken:
+ _nextChickenSequenceId = 0x144;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05GrabChicken:
+ _nextChickenSequenceId = 0x14B;
+ break;
+ case kAS05GrabLadder:
+ while (gameSys.isSequenceActive(0x149, 39) && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.insertSequence(0x14E, gnap._id + 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x14D;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[2] = 200;
+ _vm->_timers[6] = 300;
+ gnap._actionStatus = -1;
+ break;
+ case kAS05EnterBarn:
+ gameSys.insertSequence(0x107B1, 1,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gameSys.setAnimation(0x107B1, 1, 0);
+ gnap._actionStatus = kAS05LeaveScene;
+ break;
+ case kAS05UseTwigWithChicken:
+ gnap.playShowItem(5, 0, 0);
+ _nextChickenSequenceId = 0x14F;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ PlayerPlat& plat = *_vm->_plat;
+ if (plat._sequenceId == 0x146) {
+ plat._pos = Common::Point(4, 8);
+ gameSys.insertSequence(0x107C1, 160, 0x146, 256, kSeqSyncWait, 0, 300 - plat._gridX, 384 - plat._gridY);
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ plat._id = 20 * plat._pos.y;
+ _vm->invAdd(kItemNeedle);
+ _vm->setFlag(kGFNeedleTaken);
+ _vm->setGrabCursorSprite(kItemNeedle);
+ _vm->showCursor();
+ _vm->_timers[1] = 30;
+ plat._actionStatus = -1;
+ }
+ if (plat._actionStatus == kAS05PlatSearchHaystack) {
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.insertSequence(0x145, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x146, 256, 0x145, plat._id, kSeqSyncWait, 0, 0, 0);
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ plat._sequenceId = 0x146;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x146, 256, 1);
+ _vm->_timers[1] = 300;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextChickenSequenceId == 0x14B) {
+ gameSys.setAnimation(_nextChickenSequenceId, 100, 3);
+ gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x14C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x14C;
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 100, 3);
+ gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene06::Scene06(GnapEngine *vm) : Scene(vm) {
+ _horseTurnedBack = false;
+ _nextPlatSequenceId = -1;
+ _nextHorseSequenceId = -1;
+ _currHorseSequenceId = -1;
+}
+
+int Scene06::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ _vm->playSound(0x11B, false);
+ _vm->clearFlag(kGFSceneFlag1);
+ }
+ return 0x101;
+}
+
+void Scene06::updateHotspots() {
+ _vm->setHotspot(kHS06Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS06Gas, 300, 120, 440, 232, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS06Ladder, 497, 222, 614, 492, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS06Horse, 90, 226, 259, 376, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS06ExitOutsideBarn, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS06WalkArea1, 0, 0, 200, 515);
+ _vm->setHotspot(kHS06WalkArea2, 200, 0, 285, 499);
+ _vm->setHotspot(kHS06WalkArea3, 688, 0, 800, 499);
+ _vm->setHotspot(kHS06WalkArea4, 475, 469, 800, 505);
+ _vm->setHotspot(kHS06WalkArea5, 0, 0, 800, 504);
+ _vm->setDeviceHotspot(kHS06Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFGasTaken))
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ if (_vm->_cursorValue == 4) {
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS06Gas]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene06::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool triedDeviceOnGas = false;
+
+ _vm->startSoundTimerC(7);
+
+ _horseTurnedBack = false;
+ gameSys.insertSequence(0xF1, 120, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currHorseSequenceId = 0xF1;
+ _nextHorseSequenceId = -1;
+
+ gameSys.setAnimation(0xF1, 120, 2);
+ _vm->_timers[4] = _vm->getRandom(40) + 25;
+
+ if (_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0xF7, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0xF8, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFGasTaken) && _vm->_cursorValue != 4)
+ gameSys.insertSequence(0xFE, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ gnap.initPos(5, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 5, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS06Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS06Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDisguise) {
+ gnap.useDisguiseOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFKeysTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Gas:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk04)) {
+ gnap.playImpossible();
+ } else if (triedDeviceOnGas) {
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS06TryToGetGas;
+ } else {
+ triedDeviceOnGas = true;
+ gnap.playPullOutDeviceNonWorking(_vm->_hotspotsWalkPos[1]);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk04))
+ gnap.playImpossible();
+ else
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Ladder:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFGasTaken))
+ gnap.playImpossible();
+ else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS06TryToClimbLadder;
+ _vm->setFlag(kGFGasTaken);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06Horse:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTwig && _horseTurnedBack) {
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._idleFacing = kDirUpLeft;
+ plat.walkTo(Common::Point(6, 8), 1, 0x107C2, 1);
+ plat._idleFacing = kDirIdleLeft;
+ gnap._actionStatus = kAS06UseTwigOnHorse;
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 3, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 2));
+ break;
+ case TALK_CURSOR:
+ if (_horseTurnedBack) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(3, 2)) | 0x10000, 1);
+ } else {
+ gnap._idleFacing = kDirBottomLeft;
+ _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS06TalkToHorse;
+ }
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS06ExitOutsideBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS06LeaveScene;
+ if (_vm->_cursorValue == 1)
+ _vm->_newSceneNum = 5;
+ else
+ _vm->_newSceneNum = 35;
+ }
+ break;
+
+ case kHS06WalkArea1:
+ case kHS06WalkArea2:
+ case kHS06WalkArea3:
+ case kHS06WalkArea4:
+ case kHS06WalkArea5:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(40) + 25;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHorseSequenceId == -1) {
+ if (_horseTurnedBack) {
+ _nextHorseSequenceId = 0xF5;
+ } else {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ case 1:
+ case 2:
+ _nextHorseSequenceId = 0xF1;
+ break;
+ case 3:
+ _nextHorseSequenceId = 0xF3;
+ break;
+ case 4:
+ _nextHorseSequenceId = 0xF4;
+ break;
+ }
+ }
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene06::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS06LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TryToGetGas:
+ gameSys.insertSequence(0xFC, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xFC;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TryToClimbLadder:
+ gameSys.insertSequence(0xFF, 20, 0xFE, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0xFD, gnap._id, 0);
+ gameSys.insertSequence(0xFD, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xFD;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS06TryToClimbLadderDone;
+ break;
+ case kAS06TryToClimbLadderDone:
+ gnap._pos = Common::Point(6, 7);
+ gnap._actionStatus = -1;
+ break;
+ case kAS06TalkToHorse:
+ _nextHorseSequenceId = 0xF6;
+ break;
+ case kAS06UseTwigOnHorse:
+ _nextPlatSequenceId = 0xFB;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._sequenceId == 0xFA) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->invAdd(kItemGas);
+ _vm->setFlag(kGFGasTaken);
+ _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED;
+ _vm->setGrabCursorSprite(kItemGas);
+ plat._actionStatus = -1;
+ plat._pos = Common::Point(6, 8);
+ gameSys.insertSequence(0x107C1, plat._id, 0, 0, kSeqNone, 0, 450 - plat._gridX, 384 - plat._gridY);
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ _vm->setFlag(kGFUnk04);
+ gnap._actionStatus = -1;
+ _vm->showCursor();
+ }
+ if (_nextPlatSequenceId == 0xFB) {
+ gameSys.setAnimation(0, 0, 1);
+ _nextHorseSequenceId = 0xF2;
+ plat._actionStatus = 6;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextHorseSequenceId != -1) {
+ switch (_nextHorseSequenceId) {
+ case 0xF2:
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ gameSys.setAnimation(0xFA, 256, 1);
+ gameSys.insertSequence(0xF2, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x100, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xF7, 20, 0xF8, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFB, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFA, 256, 0xFB, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xFA;
+ plat._sequenceDatNum = 0;
+ gameSys.insertSequence(0x107B7, gnap._id, 0x100, gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B7;
+ gnap._sequenceDatNum = 1;
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ _nextPlatSequenceId = -1;
+ _vm->invRemove(kItemTwig);
+ break;
+ case 0xF6:
+ gameSys.setAnimation(_nextHorseSequenceId, 120, 2);
+ gameSys.insertSequence(0xF6, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ _horseTurnedBack = true;
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gameSys.setAnimation(_nextHorseSequenceId, 120, 2);
+ gameSys.insertSequence(_nextHorseSequenceId, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ _currHorseSequenceId = _nextHorseSequenceId;
+ _nextHorseSequenceId = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene07::Scene07(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene07::init() {
+ return 0x92;
+}
+
+void Scene07::updateHotspots() {
+ _vm->setHotspot(kHS07Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS07ExitHouse, 700, 125, 799, 290, SF_EXIT_NE_CURSOR);
+ _vm->setHotspot(kHS07Dice, 200, 290, 270, 360, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS07WalkArea1, 0, 0, 325, 445);
+ _vm->setHotspot(kHS07WalkArea2, 325, 0, 799, 445, _vm->_isLeavingScene ? SF_WALKABLE : SF_NONE);
+ _vm->setHotspot(kHS07WalkArea3, 160, 0, 325, 495);
+ _vm->setDeviceHotspot(kHS07Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypus))
+ _vm->_hotspots[kHS07Dice]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene07::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x8C, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x90, 1, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _vm->invRemove(kItemGas);
+ _vm->invRemove(kItemNeedle);
+
+ if (!_vm->isFlag(kGFPlatypus))
+ gameSys.insertSequence(0x8D, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 8) {
+ gnap.initPos(7, 7, kDirBottomLeft);
+ plat.initPos(9, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ } else {
+ gnap._pos = Common::Point(6, 7);
+ gnap._id = 140;
+ gnap._sequenceId = 0x8F;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.insertSequence(0x8F, 140, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS07Wait;
+ plat._pos = Common::Point(3, 8);
+ plat._id = 160;
+ plat._sequenceId = 0x91;
+ plat._sequenceDatNum = 0;
+ plat._idleFacing = kDirIdleLeft;
+ gameSys.insertSequence(0x91, 160, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[3] = 600;
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ if (_vm->testWalk(0, 1, 8, 7, 6, 7))
+ updateHotspots();
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS07Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS07ExitHouse:
+ _vm->_isLeavingScene = true;
+ if (gnap._pos.x > 8)
+ gnap.walkTo(Common::Point(gnap._pos.x, 7), 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(8, 7), 0, 0x107AD, 1);
+ gnap._actionStatus = kAS07LeaveScene;
+ break;
+
+ case kHS07Dice:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 8), 3, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ break;
+ case GRAB_CURSOR:
+ _vm->setFlag(kGFPlatypus);
+ _vm->invAdd(kItemDice);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(3, 3));
+ gameSys.setAnimation(0x8E, 1, 2);
+ gameSys.insertSequence(0x8E, 1, 141, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0)) | 0x10000, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0));
+ gnap._sequenceDatNum = 1;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS07Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kHS07WalkArea1:
+ case kHS07WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS07WalkArea3:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ gnap.updateIdleSequence();
+ if (plat._actionStatus < 0 && gnap._actionStatus < 0) {
+ if (_vm->_timers[0]) {
+ if (!_vm->_timers[1]) {
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ int gnapRandomValue = _vm->getRandom(20);
+ if (plat._idleFacing != kDirIdleLeft) {
+ if (gnapRandomValue == 0 && plat._sequenceId == 0x7CA)
+ plat.playSequence(0x107CC);
+ else if (gnapRandomValue == 1 && plat._sequenceId == 0x7CA)
+ plat.playSequence(0x10845);
+ else if (plat._pos.y == 9)
+ plat.playSequence(0x107CA);
+ } else if (gnapRandomValue == 0 && plat._sequenceId == 0x7C9)
+ plat.playSequence(0x107CB);
+ else if (gnapRandomValue == 1 && plat._sequenceId == 0x7C9)
+ plat.playSequence(0x10844);
+ else if (plat._pos.y == 9)
+ plat.playSequence(0x107C9);
+ gameSys.setAnimation(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, 1);
+ }
+ } else {
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ plat.makeRoom();
+ }
+ } else {
+ _vm->_timers[0] = 100;
+ _vm->_timers[1] = 35;
+ }
+ playRandomSound(4);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(40) + 50;
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene07::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS07LeaveScene:
+ _vm->_newSceneNum = 8;
+ _vm->_sceneDone = true;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->setGrabCursorSprite(kItemDice);
+ }
+}
+
+/*****************************************************************************/
+
+Scene08::Scene08(GnapEngine *vm) : Scene(vm) {
+ _nextDogSequenceId = -1;
+ _currDogSequenceId = -1;
+ _nextManSequenceId = -1;
+ _currManSequenceId = -1;
+}
+
+int Scene08::init() {
+ return 0x150;
+}
+
+void Scene08::updateHotspots() {
+ _vm->setHotspot(kH08SPlatypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08ExitBackdoor, 0, 280, 10, 400, SF_EXIT_L_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS08ExitCrash, 200, 590, 400, 599, SF_EXIT_D_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS08Man, 510, 150, 610, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Door, 350, 170, 500, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Meat, 405, 450, 480, 485, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Bone, 200, 405, 270, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08Toy, 540, 430, 615, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS08WalkArea1, 0, 0, 290, 340);
+ _vm->setHotspot(kHS08WalkArea2, 0, 0, 799, 420);
+ _vm->setDeviceHotspot(kHS08Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFBarnPadlockOpen))
+ _vm->_hotspots[kHS08Meat]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTruckFilledWithGas))
+ _vm->_hotspots[kHS08Bone]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ _vm->_hotspots[kHS08Toy]._flags = SF_WALKABLE | SF_DISABLED;
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene08::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ if ( _nextDogSequenceId != 0x135 )
+ _nextDogSequenceId = 0x134;
+ }
+}
+
+void Scene08::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x14F, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x14E, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currDogSequenceId = 0x135;
+ _nextDogSequenceId = 0x135;
+
+ gameSys.setAnimation(0x135, 100, 3);
+ gameSys.insertSequence(_currDogSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currManSequenceId = 0x140;
+ _nextManSequenceId = -1;
+
+ gameSys.setAnimation(0x140, 100, 2);
+ gameSys.insertSequence(_currManSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+
+ if (!_vm->isFlag(kGFBarnPadlockOpen))
+ gameSys.insertSequence(0x144, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTruckFilledWithGas))
+ gameSys.insertSequence(0x145, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFTruckKeysUsed))
+ gameSys.insertSequence(0x146, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-1, 7, kDirIdleLeft);
+
+ _vm->endSceneInit();
+
+ gnap.walkTo(Common::Point(1, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS08Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kH08SPlatypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.kissPlatypus(8);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS08ExitBackdoor:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(0, 6), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS08LeaveScene;
+ plat.walkTo(Common::Point(0, 7), 1, 0x107CF, 1);
+ _vm->_newSceneNum = 9;
+ break;
+
+ case kHS08ExitCrash:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(3, 9), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS08LeaveScene;
+ plat.walkTo(Common::Point(4, 9), 1, 0x107C1, 1);
+ _vm->_newSceneNum = 7;
+ break;
+
+ case kHS08Man:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 6), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS08LookMan;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(8, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS08TalkMan;
+ break;
+ case PLAT_CURSOR:
+ gnap.actionIdle(0x14D);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(6, 6), 1, 0x107C2, 1);
+ plat._actionStatus = kAS08PlatWithMan;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(6, 6));
+ break;
+ }
+ }
+ break;
+
+ case kHS08Door:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 7), 5, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS08GrabDog;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 0));
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS08LookDog;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS08GrabDog;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS08TalkDog;
+ break;
+ case PLAT_CURSOR:
+ _vm->setFlag(kGFSceneFlag1);
+ gnap.actionIdle(0x14D);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), 1, 0x107C2, 1);
+ plat._actionStatus = kAS08PlatWithDog;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(3, 7));
+ break;
+ }
+ }
+ break;
+
+ case kHS08Meat:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 8), 5, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 7));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(6, 7));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(6, 7));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x149;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08Bone:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(2, 7), 3, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 6));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(3, 6));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(3, 6));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x14A;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08Toy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(8, 7), 7, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 6));
+ break;
+ case GRAB_CURSOR:
+ if (_currDogSequenceId == 0x135) {
+ gnap.playScratchingHead(Common::Point(7, 6));
+ } else {
+ gnap.actionIdle(0x14D);
+ gnap.playPullOutDevice(Common::Point(7, 6));
+ gnap.playUseDevice();
+ _nextDogSequenceId = 0x14B;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS08WalkArea1:
+ case kHS08WalkArea2:
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(-1, 6), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.actionIdle(0x14D);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(50) + 125;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextManSequenceId == -1 &&
+ (_currDogSequenceId == 0x134 || _currDogSequenceId == 0x135)) {
+ int _gnapRandomValue = _vm->getRandom(4);
+ switch (_gnapRandomValue) {
+ case 0:
+ _nextManSequenceId = 0x138;
+ break;
+ case 1:
+ _nextManSequenceId = 0x136;
+ break;
+ case 2:
+ _nextManSequenceId = 0x13B;
+ break;
+ case 3:
+ _nextManSequenceId = 0x13A;
+ break;
+ }
+ }
+ }
+ playRandomSound(5);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(50) + 75;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene08::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS08LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08TalkMan:
+ _nextManSequenceId = 0x13F;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08LookMan:
+ _nextManSequenceId = 0x140;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08LookDog:
+ _nextManSequenceId = 0x137;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08GrabDog:
+ if (_currDogSequenceId == 0x135)
+ _nextDogSequenceId = 0x133;
+ else
+ _nextDogSequenceId = 0x13C;
+ gnap._actionStatus = -1;
+ break;
+ case kAS08TalkDog:
+ if (_currDogSequenceId == 0x135)
+ _nextDogSequenceId = 0x133;
+ else
+ _nextDogSequenceId = 0x13C;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS08PlatWithDog:
+ _nextDogSequenceId = 0x147;
+ break;
+ case kAS08PlatWithMan:
+ _nextManSequenceId = 0x140;
+ plat._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextManSequenceId != -1) {
+ gameSys.setAnimation(_nextManSequenceId, 100, 2);
+ gameSys.insertSequence(_nextManSequenceId, 100, _currManSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currManSequenceId = _nextManSequenceId;
+ _nextManSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_currDogSequenceId == 0x147)
+ plat._actionStatus = -1;
+ if (_currDogSequenceId == 0x149 || _currDogSequenceId == 0x14A || _currDogSequenceId == 0x14B) {
+ if (_vm->getRandom(2) != 0)
+ _nextManSequenceId = 0x13D;
+ else
+ _nextManSequenceId = 0x13E;
+ } else if (_currDogSequenceId == 0x133)
+ _nextManSequenceId = 0x139;
+ if (_nextDogSequenceId == 0x149 || _nextDogSequenceId == 0x14A || _nextDogSequenceId == 0x14B) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ switch (_nextDogSequenceId) {
+ case 0x149:
+ _vm->setFlag(kGFBarnPadlockOpen);
+ _vm->_hotspots[kHS08Meat]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x144, 1, true);
+ break;
+ case 0x14A:
+ _vm->setFlag(kGFTruckFilledWithGas);
+ _vm->_hotspots[kHS08Bone]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x145, 1, true);
+ break;
+ case 0x14B:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->_hotspots[kHS08Toy]._flags = SF_DISABLED | SF_WALKABLE;
+ gameSys.removeSequence(0x146, 1, true);
+ break;
+ }
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = 0x134;
+ } else if (_nextDogSequenceId == 0x147) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x148, 160, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ _nextDogSequenceId = 0x134;
+ plat._pos = Common::Point(1, 8);
+ plat._id = 160;
+ plat._sequenceId = 0x148;
+ plat._idleFacing = kDirIdleRight;
+ plat._sequenceDatNum = 0;
+ if (gnap._pos == Common::Point(1, 8))
+ gnap.walkStep();
+ } else if (_nextDogSequenceId != -1) {
+ gameSys.setAnimation(_nextDogSequenceId, 100, 3);
+ gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currDogSequenceId = _nextDogSequenceId;
+ if (_nextDogSequenceId != 0x135)
+ _nextDogSequenceId = 0x134;
+ if (_currDogSequenceId == 0x133) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x14D;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene09::Scene09(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene09::init() {
+ return 0x4E;
+}
+
+void Scene09::updateHotspots() {
+ _vm->setHotspot(kHS09Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS09ExitKitchen, 280, 200, 380, 400, SF_EXIT_U_CURSOR);
+ _vm->setHotspot(kHS09ExitHouse, 790, 200, 799, 450, SF_EXIT_R_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS09Trash, 440, 310, 680, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS09WalkArea1, 0, 0, 799, 400);
+ _vm->setHotspot(kHS09WalkArea2, 0, 0, 630, 450);
+ _vm->setHotspot(kHS09WalkArea2, 0, 0, 175, 495);
+ _vm->setDeviceHotspot(kHS09Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 8;
+}
+
+void Scene09::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x4D, 1, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 8) {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(4, 7, kDirBottomRight);
+ plat.initPos(5, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x10919))
+ _vm->playSound(0x10919, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS09Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+ break;
+
+ case kHS09Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS09ExitKitchen:
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 10;
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS09LeaveScene;
+ plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1);
+ plat._idleFacing = kDirIdleRight;
+ break;
+
+ case kHS09ExitHouse:
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 8;
+ gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS09LeaveScene;
+ plat.walkTo(Common::Point(10, -1), -1, 0x107CD, 1);
+ plat._idleFacing = kDirIdleRight;
+ break;
+
+ case kHS09Trash:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(9, 6), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap._actionStatus = kAS09SearchTrash;
+ gnap.walkTo(Common::Point(9, 6), 0, 0x107BC, 1);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS09WalkArea1:
+ case kHS09WalkArea2:
+ case kHS09WalkArea3:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene && gnap._actionStatus != 1 && gnap._actionStatus != 2) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(150) + 100;
+ if (_vm->_timers[4] & 1)
+ gameSys.insertSequence(0x49, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x4A, 1, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ playRandomSound(5);
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(150) + 50;
+ _vm->_timers[5] = _vm->getRandom(40) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene09::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS09LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS09SearchTrash:
+ gameSys.setAnimation(0x4C, 120, 0);
+ gameSys.insertSequence(0x4C, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x4B, 2, true);
+ gnap._sequenceId = 0x4C;
+ gnap._id = 120;
+ gnap._idleFacing = kDirUpLeft;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(9, 6);
+ gnap._actionStatus = kAS09SearchTrashDone;
+ break;
+ case kAS09SearchTrashDone:
+ gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[2] = 360;
+ _vm->_timers[4] = _vm->getRandom(150) + 100;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group0.h b/engines/gnap/scenes/group0.h
new file mode 100644
index 0000000000..e06380926d
--- /dev/null
+++ b/engines/gnap/scenes/group0.h
@@ -0,0 +1,401 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GROUP0_H
+#define GNAP_GROUP0_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS01Platypus = 0,
+ kHS01ExitTruck = 1,
+ kHS01Mud = 2,
+ kHS01Pigs = 3,
+ kHS01Spaceship = 4,
+ kHS01Device = 5,
+ kHS01WalkArea1 = 6,
+ kHS01WalkArea2 = 7,
+ kHS01WalkArea3 = 8,
+ kHS01WalkArea4 = 9,
+ kHS01WalkArea5 = 10,
+ kHS01WalkArea6 = 11,
+ kHS01WalkArea7 = 12,
+ kHS01WalkArea8 = 13
+};
+
+enum {
+ kHS02Platypus = 0,
+ kHS02Chicken = 1,
+ kHS02Truck1 = 2,
+ kHS02Truck2 = 3,
+ kHS02TruckGrill = 4,
+ kHS02Device = 5,
+ kHS02ExitHouse = 6,
+ kHS02ExitBarn = 7,
+ kHS02ExitCreek = 8,
+ kHS02ExitPigpen = 9,
+ kHS02WalkArea1 = 10,
+ kHS02WalkArea2 = 11,
+ kHS02WalkArea3 = 12,
+ kHS02WalkArea4 = 13
+};
+
+enum {
+ kHS03Platypus = 0,
+ kHS03Grass = 1,
+ kHS03ExitTruck = 2,
+ kHS03Creek = 3,
+ kHS03TrappedPlatypus = 4,
+ kHS03Device = 5,
+ kHS03WalkAreas1 = 6,
+ kHS03WalkAreas2 = 7,
+ kHS03PlatypusWalkArea = 8,
+ kHS03WalkAreas3 = 9
+};
+
+enum {
+ kHS04Platypus = 0,
+ kHS04Twig = 1,
+ kHS04Dog = 2,
+ kHS04Axe = 3,
+ kHS04Door = 4,
+ kHS04ExitTruck = 5,
+ kHS04Device = 6,
+ kHS04Window = 7,
+ kHS04ExitBarn = 8,
+ kHS04WalkArea1 = 9,
+ kHS04WalkArea2 = 10
+};
+
+enum {
+ kHS05Platypus = 0,
+ kHS05Haystack = 1,
+ kHS05Padlock = 2,
+ kHS05Ladder = 3,
+ kHS05ExitHouse = 4,
+ kHS05Chicken = 5,
+ kHS05Device = 6,
+ kHS05WalkArea1 = 7,
+ kHS05WalkArea2 = 8,
+ kHS05WalkArea3 = 9
+};
+
+enum {
+ kHS06Platypus = 0,
+ kHS06Gas = 1,
+ kHS06Ladder = 2,
+ kHS06Horse = 3,
+ kHS06ExitOutsideBarn = 4,
+ kHS06Device = 5,
+ kHS06WalkArea1 = 6,
+ kHS06WalkArea2 = 7,
+ kHS06WalkArea3 = 8,
+ kHS06WalkArea4 = 9,
+ kHS06WalkArea5 = 10
+};
+
+enum {
+ kHS07Platypus = 0,
+ kHS07ExitHouse = 1,
+ kHS07Dice = 2,
+ kHS07Device = 3,
+ kHS07WalkArea1 = 4,
+ kHS07WalkArea2 = 5,
+ kHS07WalkArea3 = 6
+};
+
+enum {
+ kH08SPlatypus = 0,
+ kHS08ExitBackdoor = 1,
+ kHS08ExitCrash = 2,
+ kHS08Man = 3,
+ kHS08Door = 4,
+ kHS08Meat = 5,
+ kHS08Bone = 6,
+ kHS08Toy = 7,
+ kHS08WalkArea1 = 8,
+ kHS08Device = 9,
+ kHS08WalkArea2 = 10
+};
+
+enum {
+ kHS09Platypus = 0,
+ kHS09ExitKitchen = 1,
+ kHS09ExitHouse = 2,
+ kHS09Trash = 3,
+ kHS09Device = 4,
+ kHS09WalkArea1 = 5,
+ kHS09WalkArea2 = 6,
+ kHS09WalkArea3 = 7
+};
+
+enum {
+ kAS01LookSpaceship = 1,
+ kAS01LookSpaceshipDone = 2,
+ kAS01LeaveScene = 3,
+ kAS01TakeMud = 5,
+ kAS01LookPigs = 6,
+ kAS01UsePigs = 7
+};
+
+enum {
+ kAS02UseTruckNoKeys = 0,
+ kAS02UseGasWithTruck = 1,
+ kAS02UseTruckGas = 2,
+ kAS02UseTruckNoGas = 3,
+ kAS02GrabTruckGrill = 5,
+ kAS02LeaveScene = 6,
+ kAS02TalkChicken = 7,
+ kAS02GrabChicken = 8,
+ kAS02GrabChickenDone = 9,
+ kAS02UseTruckNoKeysDone = 11,
+ kAS02UseGasWithTruckDone = 12,
+ kAS02UseTwigWithChicken = 16
+};
+
+enum {
+ kAS03LeaveScene = 0,
+ kAS03FreePlatypus = 1,
+ kAS03HypnotizePlat = 2,
+ kAS03HypnotizeScaredPlat= 3,
+ kAS03FreePlatypusDone = 4,
+ kAS03GrabPlatypus = 5,
+ kAS03GrabCreek = 6,
+ kAS03GrabCreekDone = 7,
+ kAS03GrabScaredPlatypus = 8
+};
+
+enum {
+ kAS04OpenDoor = 1,
+ kAS04GetKeyFirst = 2,
+ kAS04GetKeyAnother = 3,
+ kAS04LeaveScene = 4,
+ kAS04GetKeyFirstDone = 6,
+ kAS04GetKeyFirst2 = 7,
+ kAS04GetKeyAnother2 = 8,
+ kAS04GetKeyAnotherDone = 9,
+ kAS04OpenDoorDone = 10,
+ kAS04GrabDog = 12,
+ kAS04GrabAxe = 13
+};
+
+enum {
+ kAS05PlatSearchHaystack = 0,
+ kAS05TryPickPadlock = 1,
+ kAS05PickPadlock = 2,
+ kAS05TalkChicken = 3,
+ kAS05GrabChicken = 4,
+ kAS05GrabLadder = 5,
+ kAS05EnterBarn = 6,
+ kAS05UseTwigWithChicken = 11,
+ kAS05LeaveScene = 12
+};
+
+enum {
+ kAS06TryToGetGas = 0,
+ kAS06TryToClimbLadder = 1,
+ kAS06TryToClimbLadderDone = 2,
+ kAS06TalkToHorse = 3,
+ kAS06UseTwigOnHorse = 4,
+ kAS06LeaveScene = 5
+};
+
+enum {
+ kAS07Wait = 0,
+ kAS07LeaveScene = 1
+};
+
+enum {
+ kAS08LeaveScene = 0,
+ kAS08TalkMan = 1,
+ kAS08LookMan = 2,
+ kAS08LookDog = 3,
+ kAS08GrabDog = 4,
+ kAS08TalkDog = 5,
+ kAS08PlatWithMan = 6,
+ kAS08PlatWithDog = 7
+};
+
+enum {
+ kAS09LeaveScene = 0,
+ kAS09SearchTrash = 1,
+ kAS09SearchTrashDone = 2
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene01: public Scene {
+public:
+ Scene01(GnapEngine *vm);
+ virtual ~Scene01();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _pigsIdCtr;
+ int _smokeIdCtr;
+ Graphics::Surface *_spaceshipSurface;
+};
+
+class Scene02: public Scene {
+public:
+ Scene02(GnapEngine *vm);
+ virtual ~Scene02() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _truckGrillCtr;
+ int _nextChickenSequenceId;
+ int _currChickenSequenceId;
+ int _gnapTruckSequenceId;
+};
+
+class Scene03: public Scene {
+public:
+ Scene03(GnapEngine *vm);
+ virtual ~Scene03() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _platypusHypnotized;
+ bool _platypusScared;
+ int _nextPlatSequenceId;
+ int _nextFrogSequenceId;
+ int _currFrogSequenceId;
+};
+
+class Scene04: public Scene {
+public:
+ Scene04(GnapEngine *vm);
+ virtual ~Scene04() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _triedWindow;
+ int _dogIdCtr;
+ int _nextDogSequenceId;
+ int _currDogSequenceId;
+};
+
+class Scene05: public Scene {
+public:
+ Scene05(GnapEngine *vm);
+ virtual ~Scene05() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ int _nextChickenSequenceId;
+ int _currChickenSequenceId;
+};
+
+class Scene06: public Scene {
+public:
+ Scene06(GnapEngine *vm);
+ virtual ~Scene06() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+
+private:
+ bool _horseTurnedBack;
+ int _nextPlatSequenceId;
+ int _nextHorseSequenceId;
+ int _currHorseSequenceId;
+};
+
+class Scene07: public Scene {
+public:
+ Scene07(GnapEngine *vm);
+ virtual ~Scene07() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+};
+
+class Scene08: public Scene {
+public:
+ Scene08(GnapEngine *vm);
+ virtual ~Scene08() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _nextDogSequenceId;
+ int _currDogSequenceId;
+ int _nextManSequenceId;
+ int _currManSequenceId;
+};
+
+class Scene09: public Scene {
+public:
+ Scene09(GnapEngine *vm);
+ virtual ~Scene09() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {}
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP0_H
diff --git a/engines/gnap/scenes/group1.cpp b/engines/gnap/scenes/group1.cpp
new file mode 100644
index 0000000000..e50e8cc959
--- /dev/null
+++ b/engines/gnap/scenes/group1.cpp
@@ -0,0 +1,4501 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group1.h"
+
+namespace Gnap {
+
+Scene10::Scene10(GnapEngine *vm) : Scene(vm) {
+ _nextCookSequenceId = -1;
+ _currCookSequenceId = -1;
+}
+
+int Scene10::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x10F;
+}
+
+void Scene10::updateHotspots() {
+ _vm->setHotspot(kHS10Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10ExitBar, 0, 75, 85, 455, SF_EXIT_NW_CURSOR);
+ _vm->setHotspot(kHS10ExitBackdoor, 75, 590, 500, 599, SF_EXIT_D_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS10Cook, 370, 205, 495, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Tongs, 250, 290, 350, 337, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Box, 510, 275, 565, 330, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10Oven, 690, 280, 799, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS10WalkArea1, 59, 0, 495, 460);
+ _vm->setHotspot(kHS10WalkArea2, 495, 0, 650, 420);
+ _vm->setHotspot(kHS10WalkArea3, 651, 0, 725, 400);
+ _vm->setHotspot(kHS10WalkArea4, 725, 0, 799, 441);
+ _vm->setDeviceHotspot(kHS10Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 12;
+}
+
+void Scene10::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _currCookSequenceId = 0x103;
+
+ gameSys.setAnimation(0x103, 100, 2);
+ gameSys.insertSequence(0x103, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextCookSequenceId = 0x106;
+ if (!_vm->isFlag(kGFMudTaken))
+ gameSys.insertSequence(0x107, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 9) {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(1, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ }
+
+ _vm->_timers[4] = _vm->getRandom(80) + 150;
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1091E))
+ _vm->playSound(0x1091E, true);
+
+ if (!_vm->isSoundPlaying(0x1091A))
+ _vm->playSound(0x1091A, true);
+
+ _vm->updateMouseCursor();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS10Platypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan1(plat._pos);
+ else
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(10);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS10ExitBar:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(0, 7), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS10LeaveScene;
+ plat.walkTo(Common::Point(0, 7), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 11;
+ break;
+
+ case kHS10ExitBackdoor:
+ _vm->_isLeavingScene = true;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(2, 9), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS10LeaveScene;
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C7, 1);
+ _vm->_newSceneNum = 9;
+ break;
+
+ case kHS10Cook:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 8), 6, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS10AnnoyCook;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ gnap._idleFacing = kDirBottomRight;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ case PLAT_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(4, 6), -1, -1, 1);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ }
+ }
+ break;
+
+ case kHS10Tongs:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 4, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), -1, -1, 1);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ }
+ break;
+ }
+ }
+ break;
+
+ case kHS10Box:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 6), 6, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS10AnnoyCook;
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFMudTaken))
+ gnap.playMoan2(Common::Point(-1, -1));
+ else {
+ _vm->invAdd(kItemTongs);
+ _vm->setFlag(kGFMudTaken);
+ gnap.actionIdle(0x10C);
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(7, 6), 1, 0x107D2, 1);
+ plat._actionStatus = kAS10PlatWithBox;
+ plat._idleFacing = kDirIdleRight;
+ _vm->_largeSprite = gameSys.createSurface(0xC3);
+ gnap.playIdle(Common::Point(7, 6));
+ }
+ break;
+ }
+ }
+ break;
+
+ case kHS10Oven:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(9, 6), 10, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(10, 5)) | 0x10000);
+ break;
+ case GRAB_CURSOR:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(9, 6), 0, 0x107BB, 1);
+ gameSys.insertSequence(0x10E, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x10E;
+ gnap._id = 120;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(9, 6);
+ _vm->_timers[2] = 360;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS10WalkArea1:
+ case kHS10WalkArea2:
+ case kHS10WalkArea3:
+ case kHS10WalkArea4:
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS10Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.actionIdle(0x10C);
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(80) + 150;
+ _vm->playSound(0x12B, false);
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(4);
+ if (_gnapRandomValue) {
+ int sequenceId;
+ if (_gnapRandomValue == 1) {
+ sequenceId = 0x8A5;
+ } else if (_gnapRandomValue == 2) {
+ sequenceId = 0x8A6;
+ } else {
+ sequenceId = 0x8A7;
+ }
+ gameSys.insertSequence(sequenceId | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene10::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS10LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS10AnnoyCook:
+ _nextCookSequenceId = 0x105;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS10PlatWithBox:
+ _nextCookSequenceId = 0x109;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextCookSequenceId != -1) {
+
+ switch (_nextCookSequenceId) {
+ case 0x109:
+ plat._pos = Common::Point(4, 8);
+ gameSys.insertSequence(0x109, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x107C9, 160,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(0x109) + _vm->getSequenceTotalDuration(0x10A) + _vm->getSequenceTotalDuration(0x10843),
+ 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.removeSequence(0x107, 100, true);
+ _currCookSequenceId = 0x109;
+ _nextCookSequenceId = 0x843;
+ plat._sequenceId = 0x7C9;
+ plat._id = 160;
+ plat._idleFacing = kDirIdleLeft;
+ plat._sequenceDatNum = 1;
+ break;
+ case 0x843:
+ _vm->hideCursor();
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.insertSequence(0x10843, 301, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = 0x843;
+ _nextCookSequenceId = 0x10A;
+ break;
+ case 0x10A:
+ gameSys.insertSequence(_nextCookSequenceId, 100, 0x10843, 301, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ _nextCookSequenceId = 0x104;
+ _vm->showCursor();
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->delayTicksCursor(5);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->setGrabCursorSprite(kItemTongs);
+ if (plat._actionStatus == kAS10PlatWithBox)
+ plat._actionStatus = -1;
+ if (gnap._pos == Common::Point(4, 8))
+ gnap.walkStep();
+ break;
+ default:
+ gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ break;
+ }
+
+ switch (_currCookSequenceId) {
+ case 0x106:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else {
+ int rnd = _vm->getRandom(7);
+ switch (rnd) {
+ case 0:
+ _nextCookSequenceId = 0x104;
+ break;
+ case 1:
+ _nextCookSequenceId = 0x103;
+ break;
+ case 2:
+ _nextCookSequenceId = 0x106;
+ gameSys.insertSequence(0x10D, 1, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ default:
+ _nextCookSequenceId = 0x106;
+ }
+ }
+ break;
+ case 0x103:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else if (_vm->getRandom(7) == 0)
+ _nextCookSequenceId = 0x104;
+ else
+ _nextCookSequenceId = 0x106;
+ break;
+ case 0x104:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else if (_vm->getRandom(7) == 0)
+ _nextCookSequenceId = 0x103;
+ else
+ _nextCookSequenceId = 0x106;
+ break;
+ case 0x105:
+ if (gnap._actionStatus >= 0 || plat._actionStatus >= 0)
+ _nextCookSequenceId = 0x106;
+ else {
+ int rnd = _vm->getRandom(7);
+ switch (rnd) {
+ case 0:
+ _nextCookSequenceId = 0x104;
+ break;
+ case 1:
+ _nextCookSequenceId = 0x103;
+ break;
+ default:
+ _nextCookSequenceId = 0x106;
+ }
+ }
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 300;
+ gameSys.insertSequence(0x10C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x10C;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ plat._actionStatus = -1;
+ break;
+ }
+ if (_currCookSequenceId == 0x843)
+ gameSys.setAnimation(_currCookSequenceId | 0x10000, 301, 2);
+ else
+ gameSys.setAnimation(_currCookSequenceId, 100, 2);
+ }
+}
+
+void Scene10::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(_nextCookSequenceId, 100, 2);
+ gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0);
+ _currCookSequenceId = _nextCookSequenceId;
+ _nextCookSequenceId = 0x106;
+ }
+}
+
+/*****************************************************************************/
+
+Scene11::Scene11(GnapEngine *vm) : Scene(vm) {
+ _billardBallCtr = 0;
+ _nextHookGuySequenceId = -1;
+ _currHookGuySequenceId = -1;
+ _nextGoggleGuySequenceId = -1;
+ _currGoggleGuySequenceId = -1;
+}
+
+int Scene11::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->_prevSceneNum == 10 || _vm->_prevSceneNum == 13) {
+ _vm->playSound(0x108EC, false);
+ _vm->playSound(0x10928, false);
+ }
+ return 0x209;
+}
+
+void Scene11::updateHotspots() {
+ _vm->setHotspot(kHS11Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11ExitKitchen, 420, 140, 520, 345, SF_EXIT_U_CURSOR);
+ _vm->setHotspot(kHS11ExitToilet, 666, 130, 740, 364, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS11ExitLeft, 0, 350, 10, 599, SF_EXIT_L_CURSOR | SF_WALKABLE);
+ _vm->setHotspot(kHS11GoggleGuy, 90, 185, 185, 340, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11HookGuy, 210, 240, 340, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11Billard, 640, 475, 700, 530, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS11WalkArea1, 0, 0, 365, 453);
+ _vm->setHotspot(kHS11WalkArea2, 0, 0, 629, 353);
+ _vm->setHotspot(kHS11WalkArea3, 629, 0, 799, 364);
+ _vm->setHotspot(kHS11WalkArea4, 735, 0, 799, 397);
+ _vm->setHotspot(kHS11WalkArea5, 510, 540, 799, 599);
+ _vm->setDeviceHotspot(kHS11Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 13;
+}
+
+void Scene11::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool flag = true;
+
+ _vm->_timers[7] = 50;
+ _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED;
+
+ _currGoggleGuySequenceId = 0x1F9;
+ _currHookGuySequenceId = 0x201;
+
+ switch (_vm->_prevSceneNum) {
+ case 13:
+ gnap.initPos(8, 5, kDirBottomLeft);
+ plat.initPos(9, 6, kDirIdleRight);
+ break;
+ case 47:
+ gnap.initPos(8, 5, kDirBottomLeft);
+ plat.initPos(9, 5, kDirIdleRight);
+ _currGoggleGuySequenceId = 0x1FA;
+ _currHookGuySequenceId = 0x1FF;
+ _vm->_timers[7] = 180;
+ break;
+ case 12:
+ gnap.initPos(-1, 9, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ break;
+ default:
+ gnap.initPos(6, 6, kDirBottomLeft);
+ plat.initPos(6, 5, kDirIdleRight);
+ break;
+ }
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(_currHookGuySequenceId, 120, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextHookGuySequenceId = -1;
+
+ gameSys.setAnimation(_currHookGuySequenceId, 120, 3);
+ gameSys.insertSequence(_currGoggleGuySequenceId, 121, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextGoggleGuySequenceId = -1;
+
+ gameSys.setAnimation(_currGoggleGuySequenceId, 121, 2);
+
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ _vm->_timers[6] = _vm->getRandom(100) + 100;
+ _vm->endSceneInit();
+
+ if (_vm->_prevSceneNum == 12) {
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ }
+
+ gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, 40, 0, 0);
+
+ while (!_vm->_sceneDone) {
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS11Platypus:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ break;
+
+ case kHS11ExitKitchen:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(6, 5), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(6, 6), -1, -1, 1);
+ _vm->_newSceneNum = 10;
+ break;
+
+ case kHS11ExitToilet:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(8, 5), 0, 0x107BF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(8, 6), -1, -1, 1);
+ _vm->_newSceneNum = 13;
+ break;
+
+ case kHS11ExitLeft:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(-1, 8), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS11LeaveScene;
+ plat.walkTo(Common::Point(-1, 9), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 12;
+ break;
+
+ case kHS11GoggleGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemMagazine) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS11ShowMagazineToGoggleGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 6));
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS11TalkGoggleGuy;
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11HookGuy:
+ if (gnap._actionStatus < 0) {
+ gnap._idleFacing = kDirUpRight;
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 9);
+ gnap._actionStatus = kAS11ShowItemToHookGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 4, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(3, 6)) | 0x10000);
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS11GrabHookGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.walkTo(Common::Point(5, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS11TalkHookGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11Billard:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(Common::Point(9, 8));
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 8));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(9, 8), 0, 0x107BA, 1);
+ gnap._actionStatus = kAS11GrabBillardBall;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible(Common::Point(9, 8));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS11WalkArea1:
+ case kHS11WalkArea2:
+ case kHS11WalkArea3:
+ case kHS11WalkArea4:
+ case kHS11WalkArea5:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS11Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (flag && !_vm->_timers[7]) {
+ flag = false;
+ gameSys.setAnimation(0x207, 257, 4);
+ gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ plat.updateIdleSequence2();
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextGoggleGuySequenceId == -1) {
+ if (_vm->getRandom(2))
+ _nextGoggleGuySequenceId = 0x1F6;
+ else
+ _nextGoggleGuySequenceId = 0x1F9;
+ }
+ }
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHookGuySequenceId == -1) {
+ if (_currHookGuySequenceId == 0x201) {
+ switch (_vm->getRandom(7)) {
+ case 0:
+ _nextHookGuySequenceId = 0x200;
+ break;
+ case 1:
+ _nextHookGuySequenceId = 0x205;
+ break;
+ case 2:
+ _nextHookGuySequenceId = 0x202;
+ break;
+ default:
+ _nextHookGuySequenceId = 0x201;
+ break;
+ }
+ } else {
+ _nextHookGuySequenceId = 0x201;
+ }
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(3);
+ switch (_gnapRandomValue) {
+ case 0:
+ gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(50) + 75;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene11::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ if (gnap._actionStatus != kAS11GrabBillardBall)
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS11LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS11ShowMagazineToGoggleGuy:
+ _nextGoggleGuySequenceId = 0x1F7;
+ break;
+ case kAS11TalkGoggleGuy:
+ _nextGoggleGuySequenceId = 0x1FB;
+ break;
+ case kAS11GrabHookGuy:
+ _nextHookGuySequenceId = 0x204;
+ break;
+ case kAS11ShowItemToHookGuy:
+ _nextHookGuySequenceId = 0x203;
+ break;
+ case kAS11TalkHookGuy:
+ _nextHookGuySequenceId = 0x206;
+ break;
+ case kAS11GrabBillardBall:
+ if (gameSys.getAnimationStatus(2) == 2 && gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x1F4, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x1F4;
+ gnap._id = 255;
+ gnap._sequenceDatNum = 0;
+ gameSys.removeSequence(0x207, 257, true);
+ gameSys.removeSequence(0x208, 256, true);
+ _nextGoggleGuySequenceId = 0x1F8;
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2);
+ _currGoggleGuySequenceId = _nextGoggleGuySequenceId;
+ _nextGoggleGuySequenceId = -1;
+ switch (_billardBallCtr) {
+ case 0:
+ _nextHookGuySequenceId = 0x1FC;
+ break;
+ case 1:
+ _nextHookGuySequenceId = 0x1FD;
+ break;
+ default:
+ _nextHookGuySequenceId = 0x1FE;
+ break;
+ }
+ ++_billardBallCtr;
+ gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ _currHookGuySequenceId = _nextHookGuySequenceId;
+ _nextHookGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1F4) - 5, 0, 0);
+ _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED;
+ gameSys.setAnimation(0x207, 257, 4);
+ gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1FE), 0, 0);
+ gnap._actionStatus = -1;
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextGoggleGuySequenceId != -1) {
+ _vm->_timers[5] = _vm->getRandom(100) + 75;
+ gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2);
+ _currGoggleGuySequenceId = _nextGoggleGuySequenceId;
+ _nextGoggleGuySequenceId = -1;
+ if (gnap._actionStatus >= 1 && gnap._actionStatus <= 4)
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextHookGuySequenceId == 0x204) {
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ gameSys.insertSequence(0x204, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x1F5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _currHookGuySequenceId = 0x204;
+ _nextHookGuySequenceId = -1;
+ gnap._sequenceId = 0x1F5;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ _vm->_timers[2] = _vm->getRandom(20) + 70;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ if (gnap._actionStatus == kAS11GrabHookGuy)
+ gnap._actionStatus = -1;
+ } else if (_nextHookGuySequenceId != -1) {
+ gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextHookGuySequenceId, 120, 3);
+ _currHookGuySequenceId = _nextHookGuySequenceId;
+ _nextHookGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(40) + 20;
+ if (gnap._actionStatus >= 6 && gnap._actionStatus <= 9)
+ gnap._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ gameSys.setAnimation(0, 0, 4);
+ _vm->_hotspots[kHS11Billard]._flags &= ~SF_DISABLED;
+ }
+}
+
+/*****************************************************************************/
+
+Scene12::Scene12(GnapEngine *vm) : Scene(vm) {
+ _nextBeardGuySequenceId = -1;
+ _currBeardGuySequenceId = -1;
+ _nextToothGuySequenceId = -1;
+ _currToothGuySequenceId = -1;
+ _nextBarkeeperSequenceId = -1;
+ _currBarkeeperSequenceId = -1;
+}
+
+int Scene12::init() {
+ return 0x209;
+}
+
+void Scene12::updateHotspots() {
+ _vm->setHotspot(kHS12Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12ExitRight, 790, 360, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS12ToothGuy, 80, 180, 160, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12Barkeeper, 490, 175, 580, 238, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12BeardGuy, 620, 215, 720, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12Jukebox, 300, 170, 410, 355, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS12WalkArea1, 0, 0, 260, 460);
+ _vm->setHotspot(kHS12WalkArea2, 0, 0, 380, 410);
+ _vm->setHotspot(kHS12WalkArea3, 0, 0, 799, 395);
+ _vm->setHotspot(kHS12WalkArea4, 585, 0, 799, 455);
+ _vm->setDeviceHotspot(kHS12Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene12::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int v18 = 1;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x207, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x200, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currToothGuySequenceId = 0x200;
+ _nextToothGuySequenceId = -1;
+
+ gameSys.setAnimation(0x200, 50, 2);
+ gameSys.insertSequence(0x202, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currBeardGuySequenceId = 0x202;
+ _nextBeardGuySequenceId = -1;
+
+ gameSys.setAnimation(0x202, 50, 4);
+ gameSys.insertSequence(0x203, 50, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currBarkeeperSequenceId = 0x203;
+ _nextBarkeeperSequenceId = -1;
+
+ gameSys.setAnimation(0x203, 50, 3);
+
+ _vm->_timers[4] = 30;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ if (_vm->_prevSceneNum == 15) {
+ gnap.initPos(5, 6, kDirBottomRight);
+ plat.initPos(3, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(12, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS12Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS12Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS12ExitRight:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS12LeaveScene;
+ plat.walkTo(Common::Point(10, -1), -1, -1, 1);
+ _vm->_newSceneNum = 11;
+ break;
+
+ case kHS12ToothGuy:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter) {
+ _vm->_largeSprite = gameSys.createSurface(0x141);
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12QuarterToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12QuarterWithHoleToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9);
+ gnap._idleFacing = kDirUpLeft;
+ gnap._actionStatus = kAS12ShowItemToToothGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS12GrabToothGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkToothGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(3, 7), 1, 0x107D2, 1);
+ plat._actionStatus = kAS12PlatWithToothGuy;
+ plat._idleFacing = kDirIdleRight;
+ gnap.playIdle(Common::Point(2, 7));
+ break;
+ }
+ }
+ break;
+
+ case kHS12Barkeeper:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12QuarterWithBarkeeper;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12ShowItemToBarkeeper;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12LookBarkeeper;
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(6, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkBarkeeper;
+ break;
+ case PLAT_CURSOR:
+ gnap.playPullOutDevice(plat._pos);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS12PlatWithBarkeeper;
+ break;
+ }
+ }
+ break;
+
+ case kHS12BeardGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 9);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12ShowItemToBeardGuy;
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12LookBeardGuy;
+ break;
+ case GRAB_CURSOR:
+ // NOTE Bug in the original. It has 9 as flags which seems wrong here.
+ gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS12GrabBeardGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS12TalkBeardGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(7, 6), 1, 0x107C2, 1);
+ plat._actionStatus = kAS12PlatWithBeardGuy;
+ plat._idleFacing = kDirIdleLeft;
+ gnap.playIdle(Common::Point(7, 6));
+ break;
+ }
+ }
+ break;
+
+ case kHS12Jukebox:
+ _vm->_newSceneNum = 15;
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS12LeaveScene;
+ break;
+
+ case kHS12WalkArea1:
+ case kHS12WalkArea2:
+ case kHS12WalkArea3:
+ case kHS12WalkArea4:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = 15;
+ if (_nextToothGuySequenceId == -1) {
+ if (v18 == 0 && _currBeardGuySequenceId == 0x202 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ _nextToothGuySequenceId = 0x1EC;
+ else
+ _nextToothGuySequenceId = 0x204;
+ } else if (_currToothGuySequenceId != 0x200)
+ _nextToothGuySequenceId = 0x200;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (_nextBarkeeperSequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBeardGuySequenceId == 0x202 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ _nextBarkeeperSequenceId = 0x208;
+ else
+ _nextBarkeeperSequenceId = 0x1FB;
+ } else
+ _nextBarkeeperSequenceId = 0x203;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(30) + 15;
+ if (_nextBeardGuySequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0)
+ _nextBeardGuySequenceId = 0x1F2;
+ else
+ _nextBeardGuySequenceId = 0x202;
+ v18 = (v18 + 1) % 15;
+ }
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ int _gnapRandomValue = _vm->getRandom(3);
+ switch (_gnapRandomValue) {
+ case 0:
+ gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = 30;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene12::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS12LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS12TalkToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ // Easter egg
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EE;
+ }
+ break;
+ case 3:
+ break;
+ case kAS12GrabToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EF;
+ }
+ break;
+ case kAS12ShowItemToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1ED;
+ }
+ break;
+ case kAS12QuarterWithHoleToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1EA;
+ }
+ break;
+ case kAS12QuarterToToothGuy:
+ if (_vm->isKeyStatus1(Common::KEYCODE_j)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_j);
+ _nextToothGuySequenceId = 0x206;
+ } else {
+ _nextToothGuySequenceId = 0x1E9;
+ }
+ break;
+ case kAS12QuarterToToothGuyDone:
+ gnap._actionStatus = -1;
+ _vm->showCursor();
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->setGrabCursorSprite(kItemQuarterWithHole);
+ break;
+ case kAS12TalkBeardGuy:
+ _nextBeardGuySequenceId = 0x1F4;
+ break;
+ case kAS12LookBeardGuy:
+ _nextBeardGuySequenceId = 0x1F3;
+ break;
+ case kAS12GrabBeardGuy:
+ _nextBeardGuySequenceId = 0x1F1;
+ break;
+ case kAS12ShowItemToBeardGuy:
+ _nextBeardGuySequenceId = 0x1F0;
+ break;
+ case kAS12TalkBarkeeper:
+ if (_vm->getRandom(2) != 0)
+ _nextBarkeeperSequenceId = 0x1FD;
+ else
+ _nextBarkeeperSequenceId = 0x1FF;
+ break;
+ case kAS12LookBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F8;
+ break;
+ case 14:
+ _nextBarkeeperSequenceId = 0x1F6;
+ break;
+ case kAS12ShowItemToBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F5;
+ break;
+ case kAS12QuarterWithBarkeeper:
+ _nextBarkeeperSequenceId = 0x1FA;
+ break;
+ case kAS12PlatWithBarkeeper:
+ _nextBarkeeperSequenceId = 0x1F9;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS12PlatWithToothGuy:
+ _nextToothGuySequenceId = 0x1EB;
+ break;
+ case kAS12PlatWithBeardGuy:
+ _nextBeardGuySequenceId = 0x1F3;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_currToothGuySequenceId == 0x1E9) {
+ gameSys.setAnimation(0, 0, 2);
+ _vm->hideCursor();
+ gameSys.setAnimation(0x10843, 301, 0);
+ gnap._actionStatus = kAS12QuarterToToothGuyDone;
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.insertSequence(0x10843, 301, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x107B7, gnap._id, 0x10843, 301,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B7;
+ gnap._sequenceDatNum = 1;
+ _vm->setFlag(kGFTwigTaken);
+ _vm->invAdd(kItemQuarterWithHole);
+ _vm->invRemove(kItemQuarter);
+ }
+ if (_nextToothGuySequenceId == 0x1EF) {
+ gameSys.setAnimation(_nextToothGuySequenceId, 50, 2);
+ gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _currToothGuySequenceId = _nextToothGuySequenceId;
+ _nextToothGuySequenceId = -1;
+ gnap._sequenceId = 0x205;
+ gnap._sequenceDatNum = 0;
+ _vm->_timers[4] = 40;
+ _vm->_timers[2] = _vm->getRandom(20) + 70;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ if (gnap._actionStatus == kAS12GrabToothGuy)
+ gnap._actionStatus = -1;
+ } else if (_nextToothGuySequenceId != -1) {
+ gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToothGuySequenceId, 50, 2);
+ _currToothGuySequenceId = _nextToothGuySequenceId;
+ _nextToothGuySequenceId = -1;
+ _vm->_timers[4] = 50;
+ if (gnap._actionStatus >= kAS12TalkToothGuy && gnap._actionStatus <= kAS12QuarterToToothGuy && _currToothGuySequenceId != 0x1E9 &&
+ _currToothGuySequenceId != 0x1EC && _currToothGuySequenceId != 0x200)
+ gnap._actionStatus = -1;
+ if (plat._actionStatus == kAS12PlatWithToothGuy)
+ plat._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (gnap._actionStatus == kAS12PlatWithBarkeeper && _currBarkeeperSequenceId == 0x1F9) {
+ gnap._actionStatus = -1;
+ gnap.playIdle(Common::Point(7, 6));
+ _vm->_timers[5] = 0;
+ }
+ if (_nextBarkeeperSequenceId != -1) {
+ gameSys.insertSequence(_nextBarkeeperSequenceId, 50, _currBarkeeperSequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBarkeeperSequenceId, 50, 3);
+ _currBarkeeperSequenceId = _nextBarkeeperSequenceId;
+ _nextBarkeeperSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus >= kAS12TalkBarkeeper && gnap._actionStatus <= kAS12QuarterWithBarkeeper && _currBarkeeperSequenceId != 0x203 &&
+ _currBarkeeperSequenceId != 0x1FB && _currBarkeeperSequenceId != 0x208)
+ gnap._actionStatus = -1;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextBeardGuySequenceId != -1) {
+ gameSys.insertSequence(_nextBeardGuySequenceId, 50, _currBeardGuySequenceId, 50, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBeardGuySequenceId, 50, 4);
+ _currBeardGuySequenceId = _nextBeardGuySequenceId;
+ _nextBeardGuySequenceId = -1;
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus >= kAS12TalkBeardGuy && gnap._actionStatus <= kAS12ShowItemToBeardGuy && _currBeardGuySequenceId != 0x202 && _currBeardGuySequenceId != 0x1F2)
+ gnap._actionStatus = -1;
+ if (plat._actionStatus == kAS12PlatWithBeardGuy)
+ plat._actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene13::Scene13(GnapEngine *vm) : Scene(vm) {
+ _backToiletCtr = -1;
+}
+
+int Scene13::init() {
+ _vm->playSound(0x108EC, false);
+ return 0xAC;
+}
+
+void Scene13::updateHotspots() {
+ _vm->setHotspot(kHS13Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13ExitBar, 113, 160, 170, 455, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS13BackToilet, 385, 195, 478, 367, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13FrontToilet, 497, 182, 545, 432, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Urinal, 680, 265, 760, 445, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Scribble, 560, 270, 660, 370, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13Sink, 310, 520, 560, 599, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS13WalkArea1, 268, 270, 325, 385);
+ _vm->setHotspot(kHS13WalkArea2, 0, 0, 52, 599);
+ _vm->setHotspot(kHS13WalkArea3, 0, 0, 113, 550);
+ _vm->setHotspot(kHS13WalkArea4, 0, 0, 226, 438);
+ _vm->setHotspot(kHS13WalkArea5, 0, 0, 268, 400);
+ _vm->setHotspot(kHS13WalkArea6, 0, 0, 799, 367);
+ _vm->setHotspot(kHS13WalkArea7, 478, 0, 799, 401);
+ _vm->setHotspot(kHS13WalkArea8, 545, 0, 799, 473);
+ _vm->setHotspot(kHS13WalkArea9, 0, 549, 799, 599);
+ _vm->setDeviceHotspot(kHS13Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 17;
+}
+
+void Scene13::showScribble() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ _vm->hideCursor();
+ _vm->_largeSprite = gameSys.createSurface(0x6F);
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) &&
+ !_vm->isKeyStatus1(Common::KEYCODE_SPACE) && !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->_mouseClickState._left = false;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->showCursor();
+}
+
+void Scene13::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int currSoundId = 0;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 14) {
+ gnap.initPos(6, 6, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleLeft);
+ } else {
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(2, 7, kDirIdleLeft);
+ }
+
+ _vm->endSceneInit();
+
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1091A))
+ _vm->playSound(0x1091A, true);
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS13Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ }
+ break;
+
+ case kHS13Platypus:
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ break;
+ }
+ break;
+
+ case kHS13ExitBar:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(2, 7), 0, 0x107C0, 1);
+ gnap._actionStatus = kAS13LeaveScene;
+ plat.walkTo(Common::Point(2, 8), -1, -1, 1);
+ if (_vm->isFlag(kGFUnk14) || _vm->isFlag(kGFSpringTaken)) {
+ _vm->_newSceneNum = 11;
+ } else {
+ _vm->setFlag(kGFSpringTaken);
+ _vm->_newSceneNum = 47;
+ }
+ break;
+
+ case kHS13BackToilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(5, 5), 6, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ if (gnap._pos == Common::Point(5, 5)) {
+ _backToiletCtr = MIN(5, _backToiletCtr + 1);
+ gameSys.setAnimation(_backToiletCtr + 0xA3, gnap._id, 0);
+ gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqScale | kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS13Wait;
+ gnap._sequenceId = _backToiletCtr + 0xA3;
+ gnap._idleFacing = kDirUpRight;
+ gnap._sequenceDatNum = 0;
+ } else {
+ gnap.walkTo(Common::Point(5, 5), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS13BackToilet;
+ gnap._idleFacing = kDirUpRight;
+ }
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13FrontToilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 7), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.walkTo(Common::Point(6, 7), 0, 0xA9, 5);
+ gnap._actionStatus = kAS13FrontToilet;
+ gnap._idleFacing = kDirBottomRight;
+ break;
+ }
+ }
+ break;
+
+ case kHS13Scribble:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 7), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS13LookScribble;
+ gnap._idleFacing = kDirUpRight;
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 7), -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)), 1);
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13Urinal:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(8, 7), 9, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(9, 6)));
+ gnap.walkTo(gnap._pos, 0, -1, 1);
+ gnap._actionStatus = kAS13Wait;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(8, 7), 0, -1, 1);
+ gnap._actionStatus = kAS13GrabUrinal;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13Sink:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(5, 9)));
+ gnap.walkTo(gnap._pos, 0, -1, 1);
+ gnap._actionStatus = kAS13Wait;
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(4, 8), 0, 0x107B9, 1);
+ gnap._actionStatus = kAS13GrabSink;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS13WalkArea2:
+ case kHS13WalkArea3:
+ case kHS13WalkArea4:
+ case kHS13WalkArea5:
+ case kHS13WalkArea6:
+ case kHS13WalkArea7:
+ case kHS13WalkArea8:
+ case kHS13WalkArea9:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ case kHS13WalkArea1:
+ // Nothing
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (plat._pos.y == 5 || plat._pos.y == 6)
+ plat.walkTo(Common::Point(-1, 7), -1, -1, 1);
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _vm->playSound(0xD2, false);
+ break;
+ case 1:
+ _vm->playSound(0xD3, false);
+ break;
+ case 2:
+ _vm->playSound(0xD4, false);
+ break;
+ case 3:
+ _vm->playSound(0xD5, false);
+ break;
+ case 4:
+ _vm->playSound(0xD6, false);
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ int newSoundId;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ switch (_vm->getRandom(7)) {
+ case 0:
+ newSoundId = 0xD7;
+ _vm->_timers[5] = 2 * _vm->getRandom(50) + 100;
+ break;
+ case 1:
+ case 2:
+ newSoundId = 0xCF;
+ break;
+ case 3:
+ case 4:
+ newSoundId = 0xD0;
+ break;
+ default:
+ newSoundId = 0xD1;
+ break;
+ }
+ if (newSoundId != currSoundId) {
+ _vm->playSound(newSoundId, false);
+ currSoundId = newSoundId;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ _vm->_timers[5] = _vm->getRandom(50) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene13::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS13LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS13BackToilet:
+ _backToiletCtr = MIN(5, _backToiletCtr + 1);
+ gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 9, 0, 0, 0);
+ gnap._sequenceId = _backToiletCtr + 0xA3;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ break;
+ case kAS13FrontToilet:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 14;
+ break;
+ case kAS13LookScribble:
+ gnap._actionStatus = -1;
+ showScribble();
+ break;
+ case kAS13GrabSink:
+ gameSys.setAnimation(0xAB, 160, 0);
+ gameSys.insertSequence(0xAB, 160, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0xAA, 256, true);
+ gnap._sequenceId = 0xAB;
+ gnap._id = 160;
+ gnap._idleFacing = kDirBottomRight;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(4, 8);
+ _vm->_timers[2] = 360;
+ gnap._actionStatus = kAS13GrabSinkDone;
+ break;
+ case kAS13GrabSinkDone:
+ gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS13Wait:
+ gnap._actionStatus = -1;
+ break;
+ case kAS13GrabUrinal:
+ gameSys.setAnimation(0xA2, 120, 0);
+ gameSys.insertSequence(0xA2, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA2;
+ gnap._id = 120;
+ gnap._idleFacing = kDirBottomLeft;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(4, 6);
+ _vm->_timers[2] = 360;
+ gnap._actionStatus = kAS13Wait;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->_plat->_actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene14::Scene14(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene14::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x27;
+}
+
+void Scene14::updateHotspots() {
+ _vm->setHotspot(kHS14Platypus, 0, 0, 0, 0);
+ _vm->setHotspot(kHS14Exit, 0, 590, 799, 599, SF_EXIT_D_CURSOR);
+ _vm->setHotspot(kHS14Coin, 330, 390, 375, 440, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS14Toilet, 225, 250, 510, 500, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setDeviceHotspot(kHS14Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFNeedleTaken))
+ _vm->_hotspots[kHS14Coin]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 5;
+}
+
+void Scene14::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _vm->_largeSprite = nullptr;
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFNeedleTaken))
+ gameSys.insertSequence(0x23, 10, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->endSceneInit();
+
+ if (!_vm->isFlag(kGFNeedleTaken) && _vm->invHas(kItemTongs))
+ _vm->_largeSprite = gameSys.createSurface(1);
+
+ if (!_vm->isFlag(kGFNeedleTaken)) {
+ gameSys.insertSequence(0x24, 10, 0x23, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x24;
+ _vm->_timers[2] = _vm->getRandom(40) + 50;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS14Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS14Exit:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 13;
+ break;
+
+ case kHS14Coin:
+ if (_vm->_grabCursorSpriteIndex == kItemTongs) {
+ _vm->invAdd(kItemQuarter);
+ _vm->setFlag(kGFNeedleTaken);
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ gameSys.setAnimation(0x26, 10, 0);
+ gameSys.insertSequence(0x26, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ _vm->playSound(0x108E9, false);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ gameSys.insertSequence(0x25, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23, 10, 0x25, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x23;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS14Toilet:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ _vm->playSound(0x108B1, false);
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ default:
+ _vm->_mouseClickState._left = false;
+ break;
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (!_vm->isFlag(kGFNeedleTaken) && !_vm->_timers[2]) {
+ gameSys.insertSequence(0x24, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x24;
+ _vm->_timers[2] = _vm->getRandom(40) + 50;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->_largeSprite)
+ _vm->deleteSurface(&_vm->_largeSprite);
+}
+
+void Scene14::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ gameSys.setAnimation(0x10843, 301, 1);
+ gameSys.insertSequence(0x10843, 301, 0x26, 10, kSeqSyncWait, 0, 0, 0);
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 13;
+ _vm->_grabCursorSpriteIndex = kItemQuarter;
+ }
+}
+
+/*****************************************************************************/
+
+Scene15::Scene15(GnapEngine *vm) : Scene(vm) {
+ _nextRecordSequenceId = -1;
+ _currRecordSequenceId = -1;
+ _nextSlotSequenceId = -1;
+ _currSlotSequenceId = -1;
+ _nextUpperButtonSequenceId = -1;
+ _currUpperButtonSequenceId = -1;
+ _nextLowerButtonSequenceId = -1;
+ _currLowerButtonSequenceId = -1;
+}
+
+int Scene15::init() {
+ return 0xDD;
+}
+
+void Scene15::updateHotspots() {
+ _vm->setHotspot(kHS15Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS15Exit, 50, 590, 750, 599, SF_EXIT_D_CURSOR);
+ _vm->setHotspot(kHS15Button1, 210, 425, 260, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button2, 280, 425, 325, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button3, 340, 425, 385, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button4, 400, 425, 445, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button5, 460, 425, 510, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15Button6, 520, 425, 560, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonA, 205, 480, 250, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonB, 270, 480, 320, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonC, 335, 480, 380, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonD, 395, 480, 445, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonE, 460, 480, 505, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15ButtonF, 515, 480, 560, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15CoinSlot, 585, 475, 620, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS15PlayButton, 622, 431, 650, 482, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setDeviceHotspot(kHS15Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 17;
+}
+
+void Scene15::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ _currSlotSequenceId = -1;
+ _currUpperButtonSequenceId = -1;
+ _currLowerButtonSequenceId = -1;
+ _nextSlotSequenceId = -1;
+ _nextUpperButtonSequenceId = -1;
+ _nextLowerButtonSequenceId = -1;
+ _currRecordSequenceId = 0xD5;
+ _nextRecordSequenceId = -1;
+
+ gameSys.setAnimation(0xD5, 1, 0);
+ gameSys.insertSequence(_currRecordSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_hotspots[kHS15Platypus].clearRect();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS15Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS15Exit:
+ _vm->_newSceneNum = 12;
+ _vm->_isLeavingScene = true;
+ break;
+
+ case kHS15CoinSlot:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) {
+ _nextSlotSequenceId = 0xDC; // Insert coin
+ } else if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ _nextSlotSequenceId = 0xDB;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15PlayButton:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13))
+ _vm->playSound(0x108E9, false);
+ else
+ _nextSlotSequenceId = 0xDA;
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13))
+ _nextSlotSequenceId = 0xD9;
+ else
+ _nextSlotSequenceId = 0xDA;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15Button1:
+ case kHS15Button2:
+ case kHS15Button3:
+ case kHS15Button4:
+ case kHS15Button5:
+ case kHS15Button6:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ _nextUpperButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ case kHS15ButtonA:
+ case kHS15ButtonB:
+ case kHS15ButtonC:
+ case kHS15ButtonD:
+ case kHS15ButtonE:
+ case kHS15ButtonF:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ _vm->playSound(0x108E9, false);
+ break;
+ case GRAB_CURSOR:
+ _nextLowerButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5;
+ break;
+ case TALK_CURSOR:
+ _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false);
+ break;
+ case PLAT_CURSOR:
+ gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY);
+ break;
+ }
+ }
+ break;
+
+ default:
+ _vm->_mouseClickState._left = false;
+ break;
+
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene15::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ if (_vm->_isLeavingScene) {
+ _vm->_sceneDone = true;
+ } else if (_nextSlotSequenceId != -1) {
+ gameSys.setAnimation(_nextSlotSequenceId, 1, 0);
+ gameSys.insertSequence(_nextSlotSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ _currSlotSequenceId = _nextSlotSequenceId;
+ _nextSlotSequenceId = -1;
+ switch (_currSlotSequenceId) {
+ case 0xDC:
+ if (_vm->_grabCursorSpriteIndex == kItemQuarter) {
+ _vm->invRemove(kItemQuarter);
+ } else {
+ _vm->invRemove(kItemQuarterWithHole);
+ _vm->setFlag(kGFUnk13);
+ }
+ _vm->setGrabCursorSprite(-1);
+ break;
+ case 0xDB:
+ _vm->setFlag(kGFUnk14);
+ _vm->setGrabCursorSprite(-1);
+ _nextSlotSequenceId = 0xD8;
+ break;
+ case 0xD9:
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ _vm->invAdd(kItemQuarter);
+ _vm->_newGrabCursorSpriteIndex = kItemQuarter;
+ } else if (_vm->isFlag(kGFUnk13)) {
+ _vm->clearFlag(kGFUnk13);
+ _vm->invAdd(kItemQuarterWithHole);
+ _vm->_newGrabCursorSpriteIndex = kItemQuarterWithHole;
+ }
+ _vm->_newSceneNum = 12;
+ _vm->_isLeavingScene = true;
+ break;
+ case 0xD8:
+ case 0xDA:
+ if (_currUpperButtonSequenceId != -1) {
+ gameSys.removeSequence(_currUpperButtonSequenceId, 1, true);
+ _currUpperButtonSequenceId = -1;
+ }
+ if (_currLowerButtonSequenceId != -1) {
+ gameSys.removeSequence(_currLowerButtonSequenceId, 1, true);
+ _currLowerButtonSequenceId = -1;
+ }
+ break;
+ }
+ } else if (_nextRecordSequenceId != -1) {
+ gameSys.setAnimation(_nextRecordSequenceId, 1, 0);
+ gameSys.insertSequence(_nextRecordSequenceId, 1, _currRecordSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currRecordSequenceId = _nextRecordSequenceId;
+ _nextRecordSequenceId = -1;
+ if (_currRecordSequenceId == 0xD3) {
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->_newSceneNum = 16;
+ _vm->_isLeavingScene = true;
+ }
+ gameSys.removeSequence(_currUpperButtonSequenceId, 1, true);
+ _currUpperButtonSequenceId = -1;
+ gameSys.removeSequence(_currLowerButtonSequenceId, 1, true);
+ _currLowerButtonSequenceId = -1;
+ } else if (_nextUpperButtonSequenceId != -1) {
+ gameSys.setAnimation(_nextUpperButtonSequenceId, 1, 0);
+ if (_currUpperButtonSequenceId == -1)
+ gameSys.insertSequence(_nextUpperButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(_nextUpperButtonSequenceId, 1, _currUpperButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currUpperButtonSequenceId = _nextUpperButtonSequenceId;
+ _nextUpperButtonSequenceId = -1;
+ if (_currLowerButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) {
+ if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE)
+ _nextRecordSequenceId = 0xD3;
+ else
+ _nextRecordSequenceId = 0xD4;
+ }
+ } else if (_nextLowerButtonSequenceId != -1) {
+ gameSys.setAnimation(_nextLowerButtonSequenceId, 1, 0);
+ if (_currLowerButtonSequenceId == -1)
+ gameSys.insertSequence(_nextLowerButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(_nextLowerButtonSequenceId, 1, _currLowerButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currLowerButtonSequenceId = _nextLowerButtonSequenceId;
+ _nextLowerButtonSequenceId = -1;
+ if (_currUpperButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) {
+ if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE)
+ _nextRecordSequenceId = 0xD3;
+ else
+ _nextRecordSequenceId = 0xD4;
+ }
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene17::Scene17(GnapEngine *vm) : Scene(vm) {
+ _platTryGetWrenchCtr = 0;
+ _wrenchCtr = 2;
+ _nextCarWindowSequenceId = -1;
+ _nextWrenchSequenceId = -1;
+ _canTryGetWrench = true;
+ _platPhoneCtr = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+ _currWrenchSequenceId = -1;
+ _currCarWindowSequenceId = -1;
+}
+
+int Scene17::init() {
+ return 0x263;
+}
+
+void Scene17::updateHotspots() {
+ // The original is using (1, 0, 0, 0)
+ _vm->setHotspot(kHS17Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS17Phone1, 61, 280, 97, 322, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS17Phone2, 80, 204, 178, 468, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS17ExitGrubCity, 196, 207, 280, 304, SF_EXIT_U_CURSOR, 3, 5);
+ _vm->setHotspot(kHS17ExitToyStore, 567, 211, 716, 322, SF_EXIT_U_CURSOR, 5, 6);
+ _vm->setHotspot(kHS17Wrench, 586, 455, 681, 547, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS17WalkArea1, 0, 0, 800, 434);
+ _vm->setHotspot(kHS17WalkArea2, 541, 0, 800, 600);
+ _vm->setHotspot(kHS17WalkArea3, 0, 204, 173, 468);
+ _vm->setDeviceHotspot(kHS17Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFGrassTaken))
+ _vm->_hotspots[kHS17Wrench]._flags = SF_NONE;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS17Device]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS17Platypus]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 10;
+}
+
+void Scene17::update() {
+ _vm->gameUpdateTick();
+ _vm->updateMouseCursor();
+ _vm->updateGrabCursorSprite(0, 0);
+ if (_vm->_mouseClickState._left) {
+ _vm->_gnap->walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+}
+
+void Scene17::platHangUpPhone() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int savedGnapActionStatus = gnap._actionStatus;
+
+ if (plat._actionStatus == kAS17PlatPhoningAssistant) {
+ gnap._actionStatus = kAS17PlatHangUpPhone;
+ _vm->updateMouseCursor();
+ _platPhoneCtr = 0;
+ plat._actionStatus = -1;
+ gameSys.setAnimation(0x257, 254, 4);
+ gameSys.insertSequence(0x257, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x25B, plat._id, 1);
+ gameSys.insertSequence(0x25B, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0x25B;
+ plat._sequenceDatNum = 0;
+ _currPhoneSequenceId = -1;
+ _nextPhoneSequenceId = -1;
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gnap._actionStatus = savedGnapActionStatus;
+ _vm->updateMouseCursor();
+ }
+ updateHotspots();
+}
+
+void Scene17::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(8);
+ _vm->_sceneWaiting = false;
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ _vm->_timers[3] = 200;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ _vm->_timers[6] = _vm->getRandom(30) + 200;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ gameSys.insertSequence(0x25F, 20, 0, 0, kSeqNone, 0, 0, 0);
+ } else {
+ if (_vm->_s18GarbageCanPos >= 8) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 97, 1);
+ } else if (_vm->_s18GarbageCanPos >= 6) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 68, 2);
+ } else if (_vm->_s18GarbageCanPos >= 5) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 23, -1);
+ } else if (_vm->_s18GarbageCanPos >= 4) {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -11, -5);
+ } else {
+ gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -54, -8);
+ }
+ }
+
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ gameSys.insertSequence(0x262, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFGrassTaken))
+ _currWrenchSequenceId = 0x22D;
+ else
+ _currWrenchSequenceId = 0x22F;
+
+ _currCarWindowSequenceId = 0x244;
+
+ if (_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x261, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.setAnimation(_currWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_currWrenchSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gameSys.setAnimation(0, 0, 3);
+ } else {
+ gameSys.setAnimation(_currCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_currCarWindowSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+
+ _canTryGetWrench = true;
+
+ if (_vm->isFlag(kGFUnk18))
+ gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 53 || _vm->_prevSceneNum == 18 || _vm->_prevSceneNum == 20 || _vm->_prevSceneNum == 19) {
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(4, 6, kDirBottomRight);
+ plat.initPos(5, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else if (_vm->isFlag(kGFUnk27)) {
+ gnap.initPos(3, 9, kDirUpLeft);
+ plat._pos = _vm->_hotspotsWalkPos[2];
+ plat._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x257, 254, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x25A;
+ plat._sequenceDatNum = 0;
+ _vm->endSceneInit();
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatPhoningAssistant;
+ platHangUpPhone();
+ gameSys.setAnimation(0, 0, 4);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ _vm->clearFlag(kGFUnk27);
+ updateHotspots();
+ } else if (_vm->isFlag(kGFUnk25)) {
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ plat.initPos(7, 9, kDirIdleLeft);
+ gnap._pos = _vm->_hotspotsWalkPos[2];
+ gnap._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ gameSys.insertSequence(601, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 601;
+ gnap._actionStatus = kAS17GnapHangUpPhone;
+ _vm->clearFlag(kGFUnk25);
+ gameSys.insertSequence(0x251, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ gameSys.setAnimation(0x257, 254, 0);
+ gameSys.insertSequence(0x257, 254, 0x251, 254, kSeqSyncWait, 0, 0, 0);
+ } else if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ _vm->_sceneWaiting = true;
+ gnap.initPos(3, 9, kDirUpLeft);
+ plat._pos = _vm->_hotspotsWalkPos[2];
+ plat._id = 20 * _vm->_hotspotsWalkPos[2].y;
+ _currPhoneSequenceId = 0x251;
+ gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0);
+ plat._sequenceId = 0x25A;
+ plat._sequenceDatNum = 0;
+ _vm->endSceneInit();
+ gameSys.setAnimation(_currPhoneSequenceId, 254, 1);
+ plat._actionStatus = kAS17PlatPhoningAssistant;
+ updateHotspots();
+ } else if (_vm->_prevSceneNum == 18) {
+ gnap.initPos(6, 6, kDirBottomRight);
+ plat.initPos(5, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else {
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gnap.initPos(_vm->_hotspotsWalkPos[2].x, _vm->_hotspotsWalkPos[2].y, kDirBottomRight);
+ plat.initPos(1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+ _vm->clearFlag(kGFSpringTaken);
+ _vm->clearFlag(kGFUnk16);
+ _vm->endSceneInit();
+ }
+ } else {
+ gnap._pos = Common::Point(3, 6);
+ gnap._id = 120;
+ gnap._sequenceId = 0x23D;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ plat._pos = Common::Point(-1, 8);
+ plat._id = 160;
+ gameSys.insertSequence(0x241, 160, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x107C1, plat._id, 0x241, plat._id,
+ kSeqScale | kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY);
+ gameSys.insertSequence(0x22C, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->delayTicksA(2, 9);
+ _vm->endSceneInit();
+ plat._sequenceId = 0x7C1;
+ plat._sequenceDatNum = 1;
+ plat._idleFacing = kDirBottomRight;
+ plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS17Device:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == 3) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS17Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.useJointOnPlatypus();
+ } else {
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[6], 1, 0x107C2, 1);
+ gnap.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 0, 0x107BA, 1);
+ plat._actionStatus = kAS17GetWrench1;
+ gnap._actionStatus = kAS17GetWrench1;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemJoint);
+ }
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playScratchingHead(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Wrench:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFGrassTaken)) {
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 7);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_canTryGetWrench) {
+ platHangUpPhone();
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 1, 0x107C2, 1);
+ plat._actionStatus = kAS17TryGetWrench;
+ gnap._actionStatus = kAS17TryGetWrench;
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Phone1:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17PutCoinIntoPhone;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1);
+ gnap._actionStatus = kAS17GetCoinFromPhone;
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap.useDeviceOnPlatypus();
+ plat._idleFacing = kDirUpLeft;
+ plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1);
+ _vm->setFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatUsePhone;
+ gnap._actionStatus = kAS17PlatUsePhone;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17Phone2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17PutCoinIntoPhone;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 3));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS17GnapUsePhone;
+ _vm->setFlag(kGFSpringTaken);
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (_vm->isFlag(kGFUnk18)) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ gnap.useDeviceOnPlatypus();
+ plat._idleFacing = kDirUpLeft;
+ plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1);
+ _vm->setFlag(kGFUnk16);
+ plat._actionStatus = kAS17PlatUsePhone;
+ gnap._actionStatus = kAS17PlatUsePhone;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS17ExitToyStore:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS17LeaveScene;
+ if (plat._actionStatus != kAS17PlatPhoningAssistant)
+ plat.walkTo(_vm->_hotspotsWalkPos[5] + Common::Point(-1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS17ExitGrubCity:
+ if (gnap._actionStatus < 0) {
+ platHangUpPhone();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS17LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[3] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS17WalkArea1:
+ case kHS17WalkArea2:
+ case kHS17WalkArea3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence2();
+ gnap.updateIdleSequence2();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0)
+ gameSys.insertSequence(0x22B, 21, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x25C, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x25D, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x25E, 255, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+ if (plat._actionStatus < 0 && !_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ if (_vm->isFlag(kGFGrassTaken) && _nextWrenchSequenceId == -1) {
+ _nextWrenchSequenceId = 0x236;
+ } else if (_canTryGetWrench) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextWrenchSequenceId = 0x231;
+ break;
+ case 1:
+ _nextWrenchSequenceId = 0x232;
+ break;
+ case 2:
+ case 3:
+ _nextWrenchSequenceId = 0x23C;
+ break;
+ case 4:
+ case 5:
+ _nextWrenchSequenceId = 0x22E;
+ break;
+ }
+ } else {
+ --_wrenchCtr;
+ if (_wrenchCtr) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextWrenchSequenceId = 0x237;
+ break;
+ case 1:
+ _nextWrenchSequenceId = 0x238;
+ break;
+ case 2:
+ _nextWrenchSequenceId = 0x239;
+ break;
+ case 3:
+ _nextWrenchSequenceId = 0x23A;
+ break;
+ case 4:
+ _nextWrenchSequenceId = 0x23B;
+ break;
+ case 5:
+ _nextWrenchSequenceId = 0x235;
+ break;
+ }
+ } else {
+ _wrenchCtr = 2;
+ _nextWrenchSequenceId = 0x235;
+ }
+ }
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(30) + 200;
+ if (_nextCarWindowSequenceId == -1 && !_vm->isFlag(kGFGrassTaken))
+ _nextCarWindowSequenceId = 0x246;
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene17::updateAnimations() {
+ static const int kPlatPhoneSequenceIds[] = {
+ 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS17GetWrench1:
+ gnap._actionStatus = kAS17GetWrenchGnapReady;
+ break;
+ case kAS17GetCoinFromPhone:
+ gnap.playPullOutDevice(Common::Point(1, 3));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x250, 100, 0);
+ gameSys.insertSequence(0x250, 100, 591, 100, kSeqSyncWait, 0, 0, 0);
+ _vm->invAdd(kItemDiceQuarterHole);
+ _vm->clearFlag(kGFUnk18);
+ gnap._actionStatus = kAS17GetCoinFromPhoneDone;
+ break;
+ case kAS17GetCoinFromPhoneDone:
+ _vm->setGrabCursorSprite(kItemDiceQuarterHole);
+ gnap._actionStatus = -1;
+ break;
+ case kAS17PutCoinIntoPhone:
+ gameSys.setAnimation(0x24C, gnap._id, 0);
+ gameSys.insertSequence(0x24C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x24C;
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->setGrabCursorSprite(-1);
+ _vm->setFlag(kGFUnk18);
+ gnap._actionStatus = kAS17PutCoinIntoPhoneDone;
+ break;
+ case kAS17PutCoinIntoPhoneDone:
+ gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ case kAS17GnapUsePhone:
+ gameSys.setAnimation(0x24D, gnap._id, 0);
+ gameSys.insertSequence(0x24D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS17LeaveScene;
+ _vm->_newSceneNum = 53;
+ break;
+ case kAS17GnapHangUpPhone:
+ gameSys.insertSequence(0x258, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x258;
+ gnap._actionStatus = -1;
+ break;
+ case kAS17LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case kAS17TryGetWrench:
+ plat._actionStatus = -1;
+ ++_platTryGetWrenchCtr;
+ if (_platTryGetWrenchCtr % 2 != 0)
+ _nextWrenchSequenceId = 0x233;
+ else
+ _nextWrenchSequenceId = 0x234;
+ _canTryGetWrench = false;
+ break;
+ case kAS17GetWrench1:
+ _nextWrenchSequenceId = 0x230;
+ break;
+ case kAS17GetWrench2:
+ _nextCarWindowSequenceId = 0x249;
+ break;
+ case kAS17GetWrenchDone:
+ plat._actionStatus = -1;
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ break;
+ case kAS17PlatUsePhone:
+ gameSys.setAnimation(0x24E, plat._id, 1);
+ gameSys.insertSequence(0x24E, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x24E;
+ plat._actionStatus = kAS17LeaveScene;
+ _vm->_newSceneNum = 53;
+ break;
+ case kAS17PlatPhoningAssistant:
+ ++_platPhoneCtr;
+ if (_platPhoneCtr >= 7) {
+ _platPhoneCtr = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+ gameSys.insertSequence(0x25B, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x25B;
+ plat._actionStatus = -1;
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ _vm->_sceneWaiting = false;
+ updateHotspots();
+ } else {
+ _nextPhoneSequenceId = kPlatPhoneSequenceIds[_platPhoneCtr];
+ gameSys.setAnimation(_nextPhoneSequenceId, 254, 1);
+ gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x25A, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceDatNum = 0;
+ plat._sequenceId = 0x25A;
+ _currPhoneSequenceId = _nextPhoneSequenceId;
+ }
+ break;
+ case kAS17LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_nextWrenchSequenceId) {
+ case 0x233:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(0x243, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ plat._sequenceId = 0x243;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x243, plat._id, 1);
+ break;
+ case 0x234:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(0x242, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ plat._sequenceId = 0x242;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x242, plat._id, 1);
+ break;
+ case 0x231:
+ if (_vm->getRandom(2) != 0)
+ _nextCarWindowSequenceId = 0x245;
+ else
+ _nextCarWindowSequenceId = 0x248;
+ gameSys.setAnimation(0, 0, 2);
+ break;
+ case 0x232:
+ _nextCarWindowSequenceId = 0x247;
+ gameSys.setAnimation(0, 0, 2);
+ break;
+ case 0x22E:
+ case 0x235:
+ if (_nextWrenchSequenceId == 0x235)
+ _vm->_hotspots[kHS17Wrench]._flags &= ~SF_DISABLED;
+ else
+ _vm->_hotspots[kHS17Wrench]._flags |= SF_DISABLED;
+ _canTryGetWrench = !_canTryGetWrench;
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ break;
+ case 0x230:
+ if (gnap._actionStatus == kAS17GetWrenchGnapReady) {
+ gameSys.setAnimation(0, 0, 2);
+ if (_canTryGetWrench) {
+ gameSys.insertSequence(0x22E, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = 0x22E;
+ _canTryGetWrench = false;
+ }
+ gameSys.setAnimation(0x23F, plat._id, 1);
+ gameSys.insertSequence(0x10875, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23F, plat._id,
+ plat._sequenceId | (plat._sequenceDatNum << 16), plat._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 1;
+ plat._sequenceDatNum = 0;
+ gnap._sequenceId = 0x875;
+ plat._sequenceId = 0x23F;
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat._actionStatus = kAS17GetWrench2;
+ }
+ break;
+ default:
+ if (_nextWrenchSequenceId != -1) {
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextCarWindowSequenceId) {
+ case 0x246:
+ gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = _nextCarWindowSequenceId;
+ _nextCarWindowSequenceId = -1;
+ break;
+ case 0x245:
+ case 0x247:
+ case 0x248:
+ gameSys.setAnimation(_nextWrenchSequenceId, 40, 2);
+ gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(2) != 2)
+ update();
+ gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = _nextCarWindowSequenceId;
+ _nextCarWindowSequenceId = -1;
+ _currWrenchSequenceId = _nextWrenchSequenceId;
+ _nextWrenchSequenceId = -1;
+ break;
+ case 0x249:
+ gameSys.setAnimation(0x230, 40, 2);
+ gameSys.setAnimation(0x240, plat._id, 1);
+ gameSys.insertSequence(0x230, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x240, plat._id, plat._sequenceId, plat._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x23E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x23E;
+ gnap._sequenceDatNum = 0;
+ plat._sequenceId = 0x240;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0x24A, 40, 3);
+ gameSys.insertSequence(0x24A, 40, _nextCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(2) != 2) {
+ update();
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0x24A, 40, 3);
+ gameSys.insertSequence(0x24A, 40, 586, 40, kSeqSyncWait, 0, 0, 0);
+ }
+ }
+ gameSys.insertSequence(0x22D, 40, 560, 40, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x24B, 40, 3);
+ gameSys.insertSequence(0x24B, 40, 586, 40, kSeqSyncWait, 0, 0, 0);
+ _currCarWindowSequenceId = 0x24B;
+ _nextCarWindowSequenceId = -1;
+ _currWrenchSequenceId = 0x22D;
+ _nextWrenchSequenceId = -1;
+ _vm->setFlag(kGFGrassTaken);
+ gnap._actionStatus = -1;
+ plat._actionStatus = 2;
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(30) + 80;
+ break;
+ }
+ }
+
+}
+
+/*****************************************************************************/
+
+static const int kScene18SequenceIds[] = {
+ 0x219, 0x21A, 0x21B, 0x21C, 0x21D
+};
+
+Scene18::Scene18(GnapEngine *vm) : Scene(vm) {
+ _cowboyHatSurface = nullptr;
+
+ _platPhoneCtr = 0;
+ _platPhoneIter = 0;
+ _nextPhoneSequenceId = -1;
+ _currPhoneSequenceId = -1;
+}
+
+Scene18::~Scene18() {
+ delete _cowboyHatSurface;
+}
+
+int Scene18::init() {
+ _vm->_gameSys->setAnimation(0, 0, 3);
+ return 0x222;
+}
+
+void Scene18::updateHotspots() {
+ _vm->setHotspot(kHS18Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS18GarbageCan, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos - 35, _vm->_gridMinY + 230, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos + 35, _vm->_gridMinY + 318,
+ SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, _vm->_s18GarbageCanPos, 7);
+ _vm->setHotspot(kHS18ExitToyStore, 460, 238, 592, 442, SF_EXIT_U_CURSOR, 7, 7);
+ _vm->setHotspot(kHS18ExitPhoneBooth, 275, 585, 525, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS18ExitGrubCity, 0, 350, 15, 600, SF_EXIT_L_CURSOR, 0, 9);
+ _vm->setHotspot(kHS18HydrantTopValve, 100, 345, 182, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 8);
+ _vm->setHotspot(kHS18HydrantRightValve, 168, 423, 224, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS18CowboyHat, 184, 63, 289, 171, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS18WalkArea1, 0, 0, 800, 448);
+ _vm->setHotspot(kHS18WalkArea2, 0, 0, 214, 515);
+ _vm->setDeviceHotspot(kHS18Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantRightValve]._rect.left = 148;
+ _vm->_hotspots[kHS18HydrantRightValve]._rect.top = 403;
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED;
+ _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7);
+ } else {
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.top = 246;
+ }
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.left = 105;
+ _vm->_hotspots[kHS18HydrantTopValve]._rect.right = 192;
+ } else if (_vm->isFlag(kGFTruckKeysUsed)) {
+ _vm->_hotspots[kHS18GarbageCan]._rect = Common::Rect(115, 365, 168, 470);
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7);
+ }
+ if (_vm->isFlag(kGFPlatypusDisguised))
+ _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS18Device]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18Platypus]._flags = SF_DISABLED;
+ }
+ if (_vm->isFlag(kGFUnk14)) {
+ _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS18CowboyHat]._flags = SF_DISABLED;
+ }
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene18::gnapCarryGarbageCanTo(int gridX) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ int gnapSeqId, gnapId, gnapDatNum, gnapGridX;
+ int destGridX, direction;
+
+ int curGridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75;
+
+ if (curGridX >= gnap._pos.x)
+ destGridX = curGridX - 1;
+ else
+ destGridX = curGridX + 1;
+
+ if (gridX < 0)
+ gridX = 4;
+
+ if (destGridX <= gridX)
+ destGridX = gridX;
+
+ int nextGridX = _vm->_gridMaxX - 1;
+ if (nextGridX >= destGridX)
+ nextGridX = destGridX;
+
+ if (nextGridX == gnap._pos.x) {
+ gnapSeqId = gnap._sequenceId;
+ gnapId = gnap._id;
+ gnapDatNum = gnap._sequenceDatNum;
+ gnapGridX = gnap._pos.x;
+ if (gnap._pos.x <= curGridX)
+ direction = 1;
+ else
+ direction = -1;
+ } else {
+ PlayerPlat& plat = *_vm->_plat;
+ if (gnap._pos.y == plat._pos.y) {
+ if (nextGridX >= gnap._pos.x) {
+ if (nextGridX >= plat._pos.x && gnap._pos.x <= plat._pos.x)
+ plat.makeRoom();
+ } else if (nextGridX <= plat._pos.x && gnap._pos.x >= plat._pos.x) {
+ plat.makeRoom();
+ }
+ }
+ gnapSeqId = gnap._sequenceId;
+ gnapId = gnap._id;
+ gnapDatNum = gnap._sequenceDatNum;
+ gnapGridX = gnap._pos.x;
+ int seqId;
+ if (nextGridX < gnap._pos.x) {
+ direction = -1;
+ seqId = 0x204;
+ } else {
+ direction = 1;
+ seqId = 0x203;
+ }
+
+ int seqId2 = 20 * gnap._pos.y + 1;
+ do {
+ if (_vm->isPointBlocked(gnapGridX + direction, gnap._pos.y))
+ break;
+ seqId2 += direction;
+ gameSys.insertSequence(seqId, seqId2,
+ gnapSeqId | (gnapDatNum << 16), gnapId,
+ kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnapSeqId = seqId;
+ gnapId = seqId2;
+ gnapDatNum = 0;
+ gnapGridX += direction;
+ } while (nextGridX != gnapGridX);
+ }
+
+ if (direction == 1)
+ gnap._sequenceId = 0x20A;
+ else
+ gnap._sequenceId = 0x209;
+ gnap._sequenceDatNum = 0;
+
+ if (direction == 1)
+ gnap._idleFacing = kDirBottomRight;
+ else
+ gnap._idleFacing = kDirBottomLeft;
+
+ gnap._id = 20 * gnap._pos.y + 1;
+
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ gnapSeqId | (gnapDatNum << 16), gnapId,
+ kSeqScale | kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+
+ gnap._pos.x = gnapGridX;
+}
+
+void Scene18::putDownGarbageCan(int animationIndex) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (animationIndex >= 0) {
+ while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ }
+ if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight)
+ _vm->_s18GarbageCanPos = gnap._pos.x - 1;
+ else
+ _vm->_s18GarbageCanPos = gnap._pos.x + 1;
+ _vm->clearFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight) {
+ gameSys.insertSequence(0x107BA, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7BA;
+ } else {
+ gameSys.insertSequence(0x107B9, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B9;
+ }
+ gnap._sequenceDatNum = 1;
+ gameSys.insertSequence(0x1FB, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ gameSys.setAnimation(0x1FA, 19, 4);
+ gameSys.insertSequence(0x1FA, 19, 507, 19, kSeqSyncWait, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+}
+
+void Scene18::platEndPhoning(bool platFl) {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _platPhoneIter = 0;
+ _platPhoneCtr = 0;
+ plat._actionStatus = -1;
+ if (_currPhoneSequenceId != -1) {
+ gameSys.setAnimation(0x21E, 254, 3);
+ gameSys.insertSequence(0x21E, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0);
+ while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ }
+ gameSys.removeSequence(0x21F, 254, true);
+ gameSys.setAnimation(0, 0, 3);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ if (platFl) {
+ plat._actionStatus = kAS18PlatComesHere;
+ _vm->_timers[6] = 50;
+ _vm->_sceneWaiting = true;
+ }
+ _currPhoneSequenceId = -1;
+ _nextPhoneSequenceId = -1;
+ updateHotspots();
+ }
+}
+
+void Scene18::closeHydrantValve() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ gnap._actionStatus = kAS18LeaveScene;
+ _vm->updateMouseCursor();
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCan;
+ waitForGnapAction();
+ } else {
+ gnap._actionStatus = kAS18CloseRightValveNoGarbageCan;
+ waitForGnapAction();
+ }
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1);
+ gnap._actionStatus = kAS18CloseTopValve;
+ waitForGnapAction();
+ }
+}
+
+void Scene18::waitForGnapAction() {
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ while (gnap._actionStatus >= 0 && !_vm->_gameDone) {
+ updateAnimations();
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene18::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _cowboyHatSurface = nullptr;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(4);
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ _vm->queueInsertDeviceIcon();
+ _vm->clearFlag(kGFPlatypusDisguised);
+
+ if (!_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x1F8, 19, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFTruckKeysUsed)) {
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gameSys.insertSequence(0x214, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ } else {
+ gameSys.insertSequence(0x1F9, 19, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ } else {
+ gameSys.insertSequence(0x1FA, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0);
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gameSys.insertSequence(0x212, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ } else if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ gameSys.insertSequence(0x20E, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x217, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ _vm->playSound(0x22B, true);
+ }
+ }
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ if (_vm->_prevSceneNum == 17)
+ gnap.initPos(4, 11, kDirBottomRight);
+ else
+ gnap.initPos(4, 7, kDirBottomRight);
+ _platPhoneCtr = _vm->getRandom(5);
+ if (_vm->isFlag(kGFUnk27)) {
+ gameSys.insertSequence(0x21E, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _currPhoneSequenceId = -1;
+ platEndPhoning(true);
+ _vm->clearFlag(kGFUnk27);
+ } else {
+ _currPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr];
+ _platPhoneIter = 0;
+ gameSys.insertSequence(0x21F, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ }
+ if (_vm->isFlag(kGFUnk27)) {
+ platEndPhoning(true);
+ _vm->clearFlag(kGFUnk27);
+ } else {
+ gameSys.setAnimation(_currPhoneSequenceId, 254, 3);
+ }
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ } else {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ _vm->setGrabCursorSprite(kItemCowboyHat);
+ _vm->_prevSceneNum = 19;
+ }
+ if (_vm->_prevSceneNum == 17) {
+ gnap.initPos(4, 11, kDirBottomRight);
+ plat.initPos(5, 11, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ } else if (_vm->_prevSceneNum == 19) {
+ gnap.initPos(7, 7, kDirBottomRight);
+ plat.initPos(8, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(-1, 10, kDirBottomRight);
+ plat.initPos(-1, 10, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1);
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 20, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS18Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS18Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, plat._pos.x, plat._pos.y);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS18CowboyHat:
+ if (gnap._actionStatus == kAS18StandingOnHydrant) {
+ gnap._actionStatus = kAS18GrabCowboyHat;
+ _vm->_sceneWaiting = false;
+ } else if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18CowboyHat], 3, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18CowboyHat], 0, gnap.getSequenceId(kGSPullOutDeviceNonWorking, Common::Point(3, 2)) | 0x10000, 1);
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS18GarbageCan:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk14)) {
+ if (_vm->_grabCursorSpriteIndex >= 0)
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 1, 5);
+ else
+ gnap.playImpossible();
+ } else {
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ platEndPhoning(true);
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ Common::Point destPos;
+ destPos.x = _vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1);
+ destPos.y = _vm->_hotspotsWalkPos[kHS18GarbageCan].y;
+ gnap.playShowCurrItem(destPos, _vm->_hotspotsWalkPos[kHS18GarbageCan].x, _vm->_hotspotsWalkPos[kHS18GarbageCan].y);
+ } else
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (!_vm->isFlag(kGFTruckKeysUsed))
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), _vm->_hotspotsWalkPos[kHS18GarbageCan].y));
+ else if (!_vm->isFlag(kGFTruckFilledWithGas))
+ gnap.playScratchingHead(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFTruckKeysUsed)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan] + Common::Point((gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), 0),
+ -1, -1, 1);
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(_vm->_s18GarbageCanPos, gnap._pos.y)) | 0x10000, 1);
+ gnap._actionStatus = kAS18GrabGarbageCanFromStreet;
+ } else if (!_vm->isFlag(kGFTruckFilledWithGas)) {
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan], 0, -1, 1))
+ gnap._actionStatus = kAS18GrabGarbageCanFromHydrant;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18HydrantTopValve:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ // While carrying garbage can
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 0, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnapCarryGarbageCanTo(2);
+ gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant;
+ } else if (!_vm->isFlag(kGFBarnPadlockOpen)) {
+ gnapCarryGarbageCanTo(2);
+ gnap._actionStatus = kAS18PutGarbageCanOnHydrant;
+ } else {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playImpossible();
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ gnap.playImpossible();
+ break;
+ }
+ }
+ } else {
+ if (_vm->_grabCursorSpriteIndex == kItemWrench) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1);
+ gnap._actionStatus = kAS18OpenTopValve;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 1, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 5));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFBarnPadlockOpen)) {
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS18CloseTopValve;
+ } else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18HydrantRightValve:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk14)) {
+ if (_vm->_grabCursorSpriteIndex == -1) {
+ gnap.playImpossible();
+ } else {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5);
+ }
+ } else {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->_grabCursorSpriteIndex == kItemWrench) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ gnap._actionStatus = kAS18OpenRightValveWithGarbageCan;
+ else
+ gnap._actionStatus = kAS18OpenRightValveNoGarbageCan;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 5));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFTruckFilledWithGas)) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ if (_vm->isFlag(kGFTruckKeysUsed))
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCan;
+ else
+ gnap._actionStatus = kAS18CloseRightValveNoGarbageCan;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case kHS18ExitToyStore:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ if (_vm->isFlag(kGFPictureTaken)) {
+ gnap.playImpossible();
+ } else {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 19;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore], 0, 0x107C0, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ }
+ break;
+
+ case kHS18ExitPhoneBooth:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ closeHydrantValve();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 17;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _vm->setFlag(kGFUnk27);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS18ExitGrubCity:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ }
+ closeHydrantValve();
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity], 0, 0x107B2, 1);
+ gnap._actionStatus = kAS18LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ platEndPhoning(false);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity] + Common::Point(0, -1), -1, 0x107CF, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS18WalkArea1:
+ case kHS18WalkArea2:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ default:
+ if (gnap._actionStatus != kAS18StandingOnHydrant && _vm->_mouseClickState._left) {
+ if (_vm->isFlag(kGFPlatypusDisguised)) {
+ gnapCarryGarbageCanTo(-1);
+ putDownGarbageCan(0);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if ((_vm->isFlag(kGFTruckFilledWithGas) || _vm->isFlag(kGFBarnPadlockOpen)) && !_vm->isSoundPlaying(0x22B) &&
+ gnap._actionStatus != kAS18OpenRightValveNoGarbageCanDone && gnap._actionStatus != kAS18OpenRightValveNoGarbageCan &&
+ gnap._actionStatus != kAS18OpenTopValve && gnap._actionStatus != kAS18OpenTopValveDone &&
+ gnap._actionStatus != kAS18OpenRightValveWithGarbageCan && gnap._actionStatus != kAS18OpenRightValveWithGarbageCanDone)
+ _vm->playSound(0x22B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ if (plat._actionStatus == kAS18PlatComesHere) {
+ if (!_vm->_timers[6]) {
+ plat._actionStatus = -1;
+ _vm->_sceneWaiting = false;
+ plat.initPos(-1, 10, kDirIdleLeft);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ _vm->clearFlag(kGFPlatypusTalkingToAssistant);
+ }
+ } else {
+ _vm->_hotspots[kHS18WalkArea1]._rect.bottom += 48;
+ _vm->_hotspots[kHS18WalkArea2]._rect.left += 75;
+ plat.updateIdleSequence();
+ _vm->_hotspots[kHS18WalkArea2]._rect.left -= 75;
+ _vm->_hotspots[kHS18WalkArea1]._rect.bottom -= 48;
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(2) == 1)
+ gameSys.insertSequence(0x220, 255, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x221, 255, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundA();
+ }
+ if (!_vm->isFlag(kGFPlatypusDisguised))
+ gnap.updateIdleSequence();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _vm->deleteSurface(&_cowboyHatSurface);
+}
+
+void Scene18::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS18GrabGarbageCanFromStreet:
+ if (gnap._idleFacing != kDirUpRight && gnap._idleFacing != kDirBottomRight) {
+ gameSys.insertSequence(0x1FC, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - 675, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FC;
+ } else {
+ gameSys.insertSequence(0x1FD, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - 525, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FD;
+ }
+ gameSys.removeSequence(0x1FA, 19, true);
+ _vm->setFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18GrabGarbageCanFromHydrant:
+ gameSys.insertSequence(0x1FE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x1F9, 19, true);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FE;
+ _vm->clearFlag(kGFTruckKeysUsed);
+ _vm->setFlag(kGFPlatypusDisguised);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseRightValveNoGarbageCan:
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20D, 39, true);
+ gameSys.removeSequence(0x212, 39, true);
+ gameSys.removeSequence(0x211, 39, true);
+ _vm->stopSound(0x22B);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x205;
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18OpenTopValve:
+ _vm->setFlag(kGFBarnPadlockOpen);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(2, 7));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x20C, 19, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BB, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS18OpenTopValveDone;
+ break;
+ case kAS18OpenTopValveDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x208, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x216, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.removeSequence(0x20C, 19, true);
+ gameSys.setAnimation(0x217, 39, 5);
+ gameSys.insertSequence(0x217, 39, 0x216, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20E, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x208;
+ _vm->invRemove(kItemWrench);
+ _vm->setGrabCursorSprite(-1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseTopValve:
+ gameSys.insertSequence(0x206, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20E, 39, true);
+ gameSys.removeSequence(0x216, 39, true);
+ gameSys.removeSequence(0x217, 39, true);
+ _vm->stopSound(0x22B);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x206;
+ _vm->clearFlag(kGFBarnPadlockOpen);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS18GrabCowboyHat:
+ gameSys.setAnimation(0x200, gnap._id, 0);
+ gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x200;
+ gnap._actionStatus = kAS18GrabCowboyHatDone;
+ break;
+ case kAS18GrabCowboyHatDone:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _cowboyHatSurface = _vm->addFullScreenSprite(0x1D2, 255);
+ gameSys.setAnimation(0x218, 256, 0);
+ gameSys.insertSequence(0x218, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->_newSceneNum = 18;
+ _vm->invAdd(kItemCowboyHat);
+ _vm->invAdd(kItemWrench);
+ _vm->setFlag(kGFGnapControlsToyUFO);
+ _vm->setFlag(kGFUnk14);
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->setFlag(kGFUnk14); // Useless, already set
+ updateHotspots();
+ gnap._actionStatus = kAS18LeaveScene;
+ break;
+ case kAS18LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS18PutGarbageCanOnRunningHydrant:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ gameSys.requestRemoveSequence(0x211, 39);
+ gameSys.requestRemoveSequence(0x212, 39);
+ gameSys.insertSequence(0x210, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x22B);
+ gameSys.setAnimation(0x210, gnap._id, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x210;
+ gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant2;
+ break;
+ case kAS18PutGarbageCanOnRunningHydrant2:
+ _vm->playSound(0x22B, true);
+ gameSys.setAnimation(0x1FF, gnap._id, 0);
+ gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x1FF;
+ _vm->_sceneWaiting = true;
+ gnap._actionStatus = kAS18StandingOnHydrant;
+ break;
+ case kAS18StandingOnHydrant:
+ gameSys.setAnimation(0x1FF, gnap._id, 0);
+ gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ break;
+ case kAS18OpenRightValveNoGarbageCan:
+ case kAS18OpenRightValveWithGarbageCan:
+ _vm->setFlag(kGFTruckFilledWithGas);
+ updateHotspots();
+ gnap.playPullOutDevice(Common::Point(2, 7));
+ gnap.playUseDevice();
+ gameSys.insertSequence(0x20B, 19, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1);
+ _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE;
+ if (gnap._actionStatus == kAS18OpenRightValveNoGarbageCan)
+ gnap._actionStatus = kAS18OpenRightValveNoGarbageCanDone;
+ else
+ gnap._actionStatus = kAS18OpenRightValveWithGarbageCanDone;
+ break;
+ case kAS18OpenRightValveWithGarbageCanDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x213, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.requestRemoveSequence(0x1F9, 19);
+ gameSys.removeSequence(0x20B, 19, true);
+ gameSys.setAnimation(0x213, 39, 5);
+ gameSys.insertSequence(0x214, 39, 0x213, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x207;
+ _vm->invRemove(kItemWrench);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18OpenRightValveNoGarbageCanDone:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x211, 39, 0, 0, kSeqNone, 21, 0, 0);
+ gameSys.removeSequence(0x20B, 19, true);
+ gameSys.setAnimation(0x211, 39, 5);
+ gameSys.insertSequence(0x212, 39, 0x211, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->playSound(0x22B, true);
+ gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x207;
+ _vm->invRemove(kItemWrench);
+ gnap._actionStatus = -1;
+ break;
+ case kAS18CloseRightValveWithGarbageCan:
+ gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x20D, 39, true);
+ gameSys.insertSequence(0x215, 39, 0x214, 39, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x22B);
+ gameSys.setAnimation(0x1F9, 19, 0);
+ gameSys.insertSequence(0x1F9, 19, 0x215, 39, kSeqSyncWait, 0, 0, 0);
+ _vm->clearFlag(kGFTruckFilledWithGas);
+ _vm->invAdd(kItemWrench);
+ _vm->setGrabCursorSprite(kItemWrench);
+ gameSys.insertSequence(0x107B5, gnap._id, 517, gnap._id, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ updateHotspots();
+ gnap._sequenceDatNum = 1;
+ gnap._sequenceId = 0x7B5;
+ gnap._actionStatus = kAS18CloseRightValveWithGarbageCanDone;
+ break;
+ case kAS18CloseRightValveWithGarbageCanDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS18PutGarbageCanOnHydrant:
+ _vm->setFlag(kGFTruckKeysUsed);
+ _vm->clearFlag(kGFPlatypusDisguised);
+ gameSys.insertSequence(0x20F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x20F, gnap._id, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x20F;
+ gnap._actionStatus = kAS18PutGarbageCanOnHydrantDone;
+ break;
+ case kAS18PutGarbageCanOnHydrantDone:
+ gameSys.insertSequence(0x1F9, 19, 0x20F, gnap._id, kSeqNone, 0, 0, 0);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ gameSys.setAnimation(0, 0, 3);
+ ++_platPhoneIter;
+ if (_platPhoneIter <= 4) {
+ ++_platPhoneCtr;
+ _nextPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr % 5];
+ gameSys.setAnimation(_nextPhoneSequenceId, 254, 3);
+ gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x21F, 254, 0x21F, 254, kSeqSyncWait, 0, 0, 0);
+ _currPhoneSequenceId = _nextPhoneSequenceId;
+ } else {
+ platEndPhoning(true);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+static const int kS19ShopAssistantSequenceIds[] = {
+ 0x6F, 0x70, 0x71, 0x72, 0x73
+};
+
+Scene19::Scene19(GnapEngine *vm) : Scene(vm) {
+ _toyGrabCtr = 0;
+ _shopAssistantCtr = 0;
+ _currShopAssistantSequenceId = -1;
+ _nextShopAssistantSequenceId = -1;
+
+ _pictureSurface = nullptr;
+}
+
+Scene19::~Scene19() {
+ delete _pictureSurface;
+}
+
+int Scene19::init() {
+ _vm->playSound(0x79, false);
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x77 : 0x76;
+}
+
+void Scene19::updateHotspots() {
+ _vm->setHotspot(kHS19Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS19ExitOutsideToyStore, 36, 154, 142, 338, SF_EXIT_NW_CURSOR, 4, 6);
+ _vm->setHotspot(kHS19Picture, 471, 237, 525, 283, SF_DISABLED, 7, 2);
+ _vm->setHotspot(kHS19ShopAssistant, 411, 151, 575, 279, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS19Phone, 647, 166, 693, 234, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0);
+ _vm->setHotspot(kHS19Toy1, 181, 11, 319, 149, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 0);
+ _vm->setHotspot(kHS19Toy2, 284, 85, 611, 216, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 0);
+ _vm->setHotspot(kHS19Toy3, 666, 38, 755, 154, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0);
+ _vm->setHotspot(kHS19Toy4, 154, 206, 285, 327, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 3);
+ _vm->setHotspot(kHS19Toy5, 494, 301, 570, 448, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 5);
+ _vm->setHotspot(kHS19Toy6, 0, 320, 188, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6);
+ _vm->setHotspot(kHS19Toy7, 597, 434, 800, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 8);
+ _vm->setHotspot(kHS19WalkArea1, 0, 0, 170, 600);
+ _vm->setHotspot(kHS19WalkArea2, 622, 0, 800, 600);
+ _vm->setHotspot(kHS19WalkArea3, 0, 0, 800, 437);
+ _vm->setDeviceHotspot(kHS19Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ _vm->_hotspots[kHS19Toy1]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy2]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy3]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy4]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy5]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy6]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Toy7]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19ShopAssistant]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Phone]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Platypus]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS19Picture]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ }
+ _vm->_hotspotsCount = 16;
+}
+
+void Scene19::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _toyGrabCtr = 0;
+ _pictureSurface = nullptr;
+
+ gameSys.insertSequence(0x74, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x75, 254, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFPictureTaken))
+ gameSys.insertSequence(0x69, 19, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ gnap.initPos(3, 6, kDirBottomRight);
+ _currShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_vm->getRandom(5)];
+ _nextShopAssistantSequenceId = _currShopAssistantSequenceId;
+ gameSys.setAnimation(_currShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(0x6E, 254, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0);
+ _shopAssistantCtr = 0;
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1);
+ updateHotspots();
+ } else {
+ _currShopAssistantSequenceId = 0x6D;
+ _nextShopAssistantSequenceId = -1;
+ gameSys.setAnimation(0x6D, 20, 4);
+ gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[6] = _vm->getRandom(40) + 50;
+ gnap.initPos(3, 6, kDirBottomRight);
+ plat.initPos(4, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 5, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS19Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS19Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19ExitOutsideToyStore:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ _vm->_hotspots[kHS19WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107B2, 1);
+ gnap._actionStatus = kAS19LeaveScene;
+ if (_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _vm->setFlag(kGFUnk27);
+ else
+ plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(1, 0), -1, 0x107C5, 1);
+ _vm->_hotspots[kHS19WalkArea1]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS19Picture:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case GRAB_CURSOR:
+ if (!_vm->isFlag(kGFPictureTaken)) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]) | 0x10000, 1);
+ gnap._actionStatus = kAS19GrabPicture;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19ShopAssistant:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS19TalkShopAssistant;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19Toy1:
+ case kHS19Toy2:
+ case kHS19Toy3:
+ case kHS19Toy4:
+ case kHS19Toy5:
+ case kHS19Toy6:
+ case kHS19Toy7:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]);
+ gnap._actionStatus = kAS19GrabToy;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19Phone:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 9, 1);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 1));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1);
+ gnap.playIdle(Common::Point(8, 2));
+ gnap._actionStatus = kAS19UsePhone;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS19WalkArea1:
+ case kHS19WalkArea2:
+ case kHS19WalkArea3:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ gnap.updateIdleSequence();
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) {
+ plat.updateIdleSequence();
+ if (!_vm->_timers[6] && _nextShopAssistantSequenceId == -1) {
+ _vm->_timers[6] = _vm->getRandom(40) + 50;
+ if (_vm->getRandom(4) != 0) {
+ _nextShopAssistantSequenceId = 0x64;
+ } else if (_vm->isFlag(kGFPictureTaken)) {
+ _nextShopAssistantSequenceId = 0x64;
+ } else {
+ _nextShopAssistantSequenceId = 0x6C;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_pictureSurface)
+ _vm->deleteSurface(&_pictureSurface);
+}
+
+void Scene19::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS19UsePhone:
+ _nextShopAssistantSequenceId = 0x67;
+ break;
+ case kAS19GrabToy:
+ ++_toyGrabCtr;
+ switch (_toyGrabCtr) {
+ case 1:
+ _nextShopAssistantSequenceId = 0x62;
+ break;
+ case 2:
+ _nextShopAssistantSequenceId = 0x6B;
+ break;
+ case 3:
+ _nextShopAssistantSequenceId = 0x66;
+ break;
+ default:
+ _nextShopAssistantSequenceId = 0x65;
+ break;
+ }
+ break;
+ case kAS19GrabPicture:
+ gnap.playPullOutDevice(Common::Point(6, 2));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x68, 19, 0);
+ gameSys.insertSequence(0x68, 19, 105, 19, kSeqSyncWait, 0, 0, 0);
+ _vm->invAdd(kItemPicture);
+ _vm->setFlag(kGFPictureTaken);
+ updateHotspots();
+ gnap._actionStatus = kAS19GrabPictureDone;
+ break;
+ case kAS19GrabPictureDone:
+ _vm->setGrabCursorSprite(-1);
+ _vm->hideCursor();
+ _pictureSurface = _vm->addFullScreenSprite(0xF, 255);
+ gameSys.setAnimation(0x61, 256, 0);
+ gameSys.insertSequence(0x61, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->setFlag(kGFUnk27);
+ _vm->showCursor();
+ _vm->_newSceneNum = 17;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ case kAS19TalkShopAssistant:
+ _nextShopAssistantSequenceId = 0x6D;
+ gnap._actionStatus = -1;
+ break;
+ case kAS19LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ switch (_nextShopAssistantSequenceId) {
+ case 0x6F:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ _shopAssistantCtr = (_shopAssistantCtr + 1) % 5;
+ _nextShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_shopAssistantCtr];
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x6E, 254, 0x6E, 254, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ break;
+ case 0x62:
+ case 0x66:
+ case 0x6B:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ _vm->_timers[5] = 10;
+ while (_vm->_timers[5] && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gnap.playIdle(Common::Point(6, 2));
+ gnap._actionStatus = -1;
+ break;
+ case 0x67:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ case 0x65:
+ gnap.playIdle(Common::Point(6, 2));
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 0);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ _vm->_newSceneNum = 18;
+ gnap._actionStatus = kAS19LeaveScene;
+ break;
+ case 0x6D:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x69, 19, 0x69, 19, kSeqSyncWait, _vm->getSequenceTotalDuration(_nextShopAssistantSequenceId), 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ case 0x64:
+ case 0x6C:
+ gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4);
+ gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currShopAssistantSequenceId = _nextShopAssistantSequenceId;
+ _nextShopAssistantSequenceId = -1;
+ break;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group1.h b/engines/gnap/scenes/group1.h
new file mode 100644
index 0000000000..30771d017a
--- /dev/null
+++ b/engines/gnap/scenes/group1.h
@@ -0,0 +1,454 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GROUP1_H
+#define GNAP_GROUP1_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS10Platypus = 0,
+ kHS10ExitBar = 1,
+ kHS10ExitBackdoor = 2,
+ kHS10Cook = 3,
+ kHS10Tongs = 4,
+ kHS10Box = 5,
+ kHS10Oven = 6,
+ kHS10WalkArea1 = 7,
+ kHS10Device = 8,
+ kHS10WalkArea2 = 9,
+ kHS10WalkArea3 = 10,
+ kHS10WalkArea4 = 11
+};
+
+enum {
+ kHS11Platypus = 0,
+ kHS11ExitKitchen = 1,
+ kHS11ExitToilet = 2,
+ kHS11ExitLeft = 3,
+ kHS11GoggleGuy = 4,
+ kHS11HookGuy = 5,
+ kHS11Billard = 6,
+ kHS11WalkArea1 = 7,
+ kHS11Device = 8,
+ kHS11WalkArea2 = 9,
+ kHS11WalkArea3 = 10,
+ kHS11WalkArea4 = 11,
+ kHS11WalkArea5 = 12
+};
+
+enum {
+ kHS12Platypus = 0,
+ kHS12ExitRight = 1,
+ kHS12ToothGuy = 2,
+ kHS12Barkeeper = 3,
+ kHS12BeardGuy = 4,
+ kHS12Jukebox = 5,
+ kHS12WalkArea1 = 6,
+ kHS12Device = 7,
+ kHS12WalkArea2 = 8,
+ kHS12WalkArea3 = 9,
+ kHS12WalkArea4 = 10
+};
+
+enum {
+ kHS13Platypus = 0,
+ kHS13ExitBar = 1,
+ kHS13WalkArea1 = 2,
+ kHS13BackToilet = 3,
+ kHS13FrontToilet= 4,
+ kHS13Urinal = 5,
+ kHS13Scribble = 6,
+ kHS13Sink = 7,
+ kHS13WalkArea2 = 8,
+ kHS13Device = 9,
+ kHS13WalkArea3 = 10,
+ kHS13WalkArea4 = 11,
+ kHS13WalkArea5 = 12,
+ kHS13WalkArea6 = 13,
+ kHS13WalkArea7 = 14,
+ kHS13WalkArea8 = 15,
+ kHS13WalkArea9 = 16
+};
+
+enum {
+ kHS14Platypus = 0,
+ kHS14Exit = 1,
+ kHS14Coin = 2,
+ kHS14Toilet = 3,
+ kHS14Device = 4
+};
+
+enum {
+ kHS15Platypus = 0,
+ kHS15Exit = 1,
+ kHS15Button1 = 2,
+ kHS15Button2 = 3,
+ kHS15Button3 = 4,
+ kHS15Button4 = 5,
+ kHS15Button5 = 6,
+ kHS15Button6 = 7,
+ kHS15ButtonA = 8,
+ kHS15ButtonB = 9,
+ kHS15ButtonC = 10,
+ kHS15ButtonD = 11,
+ kHS15ButtonE = 12,
+ kHS15ButtonF = 13,
+ kHS15CoinSlot = 14,
+ kHS15PlayButton = 15,
+ kHS15Device = 16
+};
+
+enum {
+ kHS17Platypus = 0,
+ kHS17Phone1 = 1,
+ kHS17Phone2 = 2,
+ kHS17ExitGrubCity = 3,
+ kHS17Device = 4,
+ kHS17ExitToyStore = 5,
+ kHS17Wrench = 6,
+ kHS17WalkArea1 = 7,
+ kHS17WalkArea2 = 8,
+ kHS17WalkArea3 = 9
+};
+
+enum {
+ kHS18Platypus = 0,
+ kHS18GarbageCan = 1,
+ kHS18Device = 2,
+ kHS18ExitToyStore = 3,
+ kHS18ExitPhoneBooth = 4,
+ kHS18ExitGrubCity = 5,
+ kHS18HydrantTopValve = 6,
+ kHS18HydrantRightValve = 7,
+ kHS18CowboyHat = 8,
+ kHS18WalkArea1 = 9,
+ kHS18WalkArea2 = 10
+};
+
+enum {
+ kHS19Platypus = 0,
+ kHS19ExitOutsideToyStore= 1,
+ kHS19Device = 2,
+ kHS19Picture = 3,
+ kHS19ShopAssistant = 4,
+ kHS19Toy1 = 5,
+ kHS19Toy2 = 6,
+ kHS19Toy3 = 7,
+ kHS19Phone = 8,
+ kHS19Toy4 = 9,
+ kHS19Toy5 = 10,
+ kHS19Toy6 = 11,
+ kHS19Toy7 = 12,
+ kHS19WalkArea1 = 13,
+ kHS19WalkArea2 = 14,
+ kHS19WalkArea3 = 15
+};
+
+enum {
+ kAS10LeaveScene = 0,
+ kAS10AnnoyCook = 1,
+ kAS10PlatWithBox = 4
+};
+
+enum {
+ kAS11LeaveScene = 0,
+ kAS11ShowMagazineToGoggleGuy = 3,
+ kAS11TalkGoggleGuy = 4,
+ kAS11GrabHookGuy = 6,
+ kAS11ShowItemToHookGuy = 8,
+ kAS11TalkHookGuy = 9,
+ kAS11GrabBillardBall = 11
+};
+
+enum {
+ kAS12LeaveScene = 0,
+ kAS12QuarterToToothGuyDone = 1,
+ kAS12TalkToothGuy = 2,
+ kAS12GrabToothGuy = 4,
+ kAS12ShowItemToToothGuy = 5,
+ kAS12QuarterWithHoleToToothGuy = 6,
+ kAS12QuarterToToothGuy = 7,
+ kAS12TalkBeardGuy = 8,
+ kAS12LookBeardGuy = 9,
+ kAS12GrabBeardGuy = 10,
+ kAS12ShowItemToBeardGuy = 11,
+ kAS12TalkBarkeeper = 12,
+ kAS12LookBarkeeper = 13,
+ kAS12ShowItemToBarkeeper = 15,
+ kAS12QuarterWithBarkeeper = 16,
+ kAS12PlatWithBarkeeper = 17,
+ kAS12PlatWithToothGuy = 18,
+ kAS12PlatWithBeardGuy = 19
+};
+
+enum {
+ kAS13LeaveScene = 0,
+ kAS13BackToilet = 1,
+ kAS13FrontToilet = 2,
+ kAS13LookScribble = 6,
+ kAS13GrabSink = 7,
+ kAS13GrabSinkDone = 8,
+ kAS13Wait = 12,
+ kAS13GrabUrinal = 13
+};
+
+enum {
+ kAS17TryGetWrench = 0,
+ kAS17GetWrench2 = 1,
+ kAS17GetWrenchDone = 2,
+ kAS17GetWrench1 = 3,
+ kAS17PlatUsePhone = 4,
+ kAS17PutCoinIntoPhone = 5,
+ kAS17GetCoinFromPhone = 6,
+ kAS17GetCoinFromPhoneDone = 7,
+ kAS17PutCoinIntoPhoneDone = 8,
+ kAS17GnapUsePhone = 9,
+ kAS17GetWrenchGnapReady = 10,
+ kAS17GnapHangUpPhone = 11,
+ kAS17PlatPhoningAssistant = 12,
+ kAS17PlatHangUpPhone = 14,
+ kAS17LeaveScene = 15
+};
+
+enum {
+ kAS18OpenRightValveNoGarbageCanDone = 0,
+ kAS18OpenRightValveNoGarbageCan = 1,
+ kAS18CloseRightValveNoGarbageCan = 2,
+ kAS18OpenTopValveDone = 3,
+ kAS18OpenTopValve = 4,
+ kAS18CloseTopValve = 5,
+ kAS18GrabGarbageCanFromStreet = 6,
+ kAS18GrabCowboyHat = 7,
+ kAS18GrabGarbageCanFromHydrant = 8,
+ kAS18PutGarbageCanOnRunningHydrant = 9,
+ kAS18PutGarbageCanOnRunningHydrant2 = 10,
+ kAS18GrabCowboyHatDone = 11,
+ kAS18StandingOnHydrant = 12,
+ kAS18OpenRightValveWithGarbageCan = 13,
+ kAS18OpenRightValveWithGarbageCanDone = 14,
+ kAS18CloseRightValveWithGarbageCan = 15,
+ kAS18PutGarbageCanOnHydrant = 16,
+ kAS18PutGarbageCanOnHydrantDone = 17,
+ kAS18PlatComesHere = 18,
+ kAS18CloseRightValveWithGarbageCanDone = 19,
+ kAS18LeaveScene = 20
+};
+
+enum {
+ kAS19UsePhone = 0,
+ kAS19GrabToy = 1,
+ kAS19GrabPicture = 2,
+ kAS19GrabPictureDone = 3,
+ kAS19TalkShopAssistant = 4,
+ kAS19LeaveScene = 5
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene10: public Scene {
+public:
+ Scene10(GnapEngine *vm);
+ virtual ~Scene10() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _nextCookSequenceId;
+ int _currCookSequenceId;
+};
+
+class Scene11: public Scene {
+public:
+ Scene11(GnapEngine *vm);
+ virtual ~Scene11() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _billardBallCtr;
+ int _nextHookGuySequenceId;
+ int _currHookGuySequenceId;
+ int _nextGoggleGuySequenceId;
+ int _currGoggleGuySequenceId;
+};
+
+class Scene12: public Scene {
+public:
+ Scene12(GnapEngine *vm);
+ virtual ~Scene12() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextBeardGuySequenceId;
+ int _currBeardGuySequenceId;
+ int _nextToothGuySequenceId;
+ int _currToothGuySequenceId;
+ int _nextBarkeeperSequenceId;
+ int _currBarkeeperSequenceId;
+};
+
+class Scene13: public Scene {
+public:
+ Scene13(GnapEngine *vm);
+ virtual ~Scene13() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _backToiletCtr;
+
+ void showScribble();
+};
+
+class Scene14: public Scene {
+public:
+ Scene14(GnapEngine *vm);
+ virtual ~Scene14() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene15: public Scene {
+public:
+ Scene15(GnapEngine *vm);
+ virtual ~Scene15() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextRecordSequenceId;
+ int _currRecordSequenceId;
+ int _nextSlotSequenceId;
+ int _currSlotSequenceId;
+ int _nextUpperButtonSequenceId;
+ int _currUpperButtonSequenceId;
+ int _nextLowerButtonSequenceId;
+ int _currLowerButtonSequenceId;
+};
+
+class Scene17: public Scene {
+public:
+ Scene17(GnapEngine *vm);
+ virtual ~Scene17() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _canTryGetWrench;
+ int _wrenchCtr;
+ int _platPhoneCtr;
+ int _platTryGetWrenchCtr;
+ int _nextPhoneSequenceId;
+ int _currPhoneSequenceId;
+ int _nextWrenchSequenceId;
+ int _currWrenchSequenceId;
+ int _nextCarWindowSequenceId;
+ int _currCarWindowSequenceId;
+
+ void update();
+ void platHangUpPhone();
+};
+
+class Scene18: public Scene {
+public:
+ Scene18(GnapEngine *vm);
+ virtual ~Scene18();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ Graphics::Surface *_cowboyHatSurface;
+
+ int _platPhoneCtr;
+ int _platPhoneIter;
+ int _nextPhoneSequenceId;
+ int _currPhoneSequenceId;
+
+ void gnapCarryGarbageCanTo(int a5);
+ void putDownGarbageCan(int animationIndex);
+ void platEndPhoning(bool platFl);
+ void closeHydrantValve();
+ void waitForGnapAction();
+};
+
+class Scene19: public Scene {
+public:
+ Scene19(GnapEngine *vm);
+ virtual ~Scene19();
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currShopAssistantSequenceId;
+ int _nextShopAssistantSequenceId;
+ int _toyGrabCtr;
+ int _shopAssistantCtr;
+
+ Graphics::Surface *_pictureSurface;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP1_H
diff --git a/engines/gnap/scenes/group2.cpp b/engines/gnap/scenes/group2.cpp
new file mode 100644
index 0000000000..1db3144c2d
--- /dev/null
+++ b/engines/gnap/scenes/group2.cpp
@@ -0,0 +1,3424 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group2.h"
+
+namespace Gnap {
+
+Scene20::Scene20(GnapEngine *vm) : Scene(vm) {
+ _stonerGuyCtr = 3;
+ _stonerGuyShowingJoint = false;
+ _groceryStoreGuyCtr = 0;
+ _currStonerGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ _currGroceryStoreGuySequenceId = -1;
+ _nextGroceryStoreGuySequenceId = -1;
+}
+
+int Scene20::init() {
+ return 0x186;
+}
+
+void Scene20::updateHotspots() {
+ _vm->setHotspot(kHS20Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS20GroceryStoreHat, 114, 441, 174, 486, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 7);
+ _vm->setHotspot(kHS20ExitParkingLot, 0, 300, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7);
+ _vm->setHotspot(kHS20StonerGuy, 276, 290, 386, 450, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS20GroceryStoreGuy, 123, 282, 258, 462, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS20ExitInsideGrubCity, 519, 250, 581, 413, SF_EXIT_L_CURSOR, 8, 7);
+ _vm->setHotspot(kHS20ExitOutsideCircusWorld, 660, 222, 798, 442, SF_EXIT_NE_CURSOR, 9, 6);
+ _vm->setHotspot(kHS20ExitOutsideToyStore, 785, 350, 800, 600, SF_EXIT_R_CURSOR, 11, 8);
+ _vm->setHotspot(kHS20ExitPhone, 250, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS20WalkArea1, 0, 0, 800, 468);
+ _vm->setHotspot(kHS20WalkArea2, 605, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS20Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 12;
+}
+
+void Scene20::updateAnimationsCb() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_nextStonerGuySequenceId) {
+ case 0x16B:
+ if (!_vm->_timers[4]) {
+ _stonerGuyShowingJoint = false;
+ gameSys.insertSequence(0x16B, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16B;
+ _nextStonerGuySequenceId = -1;
+ }
+ break;
+ case 0x16A:
+ // Grab joint
+ gnap.playPullOutDevice(Common::Point(4, 4));
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x16A, 21, 0);
+ gameSys.insertSequence(0x16A, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16A;
+ _nextStonerGuySequenceId = -1;
+ _vm->invAdd(kItemJoint);
+ _vm->setFlag(kGFJointTaken);
+ _stonerGuyShowingJoint = false;
+ gnap._actionStatus = kAS20GrabJointDone;
+ break;
+ case 0x16E:
+ gameSys.setAnimation(0x16E, 21, 2);
+ gameSys.insertSequence(0x16E, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16E;
+ _nextStonerGuySequenceId = -1;
+ _nextGroceryStoreGuySequenceId = 0x175;
+ break;
+ case 0x16D:
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 0);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ gnap._actionStatus = kAS20ActionDone;
+ break;
+ case 0x16F:
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ gameSys.setAnimation(0x17A, 20, 3);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17A, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = 0x17A;
+ _nextGroceryStoreGuySequenceId = -1;
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ case 0x171:
+ _stonerGuyCtr = (_stonerGuyCtr + 1) % 3;
+ switch (_stonerGuyCtr) {
+ case 1:
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ case 2:
+ _nextStonerGuySequenceId = 0x172;
+ break;
+ case 3:
+ _nextStonerGuySequenceId = 0x173;
+ break;
+ default:
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ }
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17C, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x17C, 20, 3);
+ gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2);
+ _currGroceryStoreGuySequenceId = 0x17C;
+ _nextGroceryStoreGuySequenceId = -1;
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ default:
+ _nextStonerGuySequenceId = 0x16C;
+ gameSys.setAnimation(0x16C, 21, 2);
+ gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = _nextStonerGuySequenceId;
+ _nextStonerGuySequenceId = -1;
+ break;
+ }
+ }
+}
+
+void Scene20::stopSounds() {
+ _vm->stopSound(0x18E);
+ _vm->stopSound(0x18F);
+ _vm->stopSound(0x190);
+ _vm->stopSound(0x191);
+ _vm->stopSound(0x194);
+ _vm->stopSound(0x195);
+ _vm->stopSound(0x192);
+ _vm->stopSound(0x193);
+ _vm->stopSound(0x196);
+ _vm->stopSound(0x197);
+ _vm->stopSound(0x198);
+ _vm->stopSound(0x199);
+ _vm->stopSound(0x19A);
+}
+
+void Scene20::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(8);
+
+ _stonerGuyShowingJoint = false;
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ _stonerGuyCtr = (_stonerGuyCtr + 1) % 3;
+ switch (_stonerGuyCtr) {
+ case 1:
+ _currStonerGuySequenceId = 0x171;
+ break;
+ case 2:
+ _currStonerGuySequenceId = 0x172;
+ break;
+ case 3:
+ _currStonerGuySequenceId = 0x173;
+ break;
+ }
+
+ _nextStonerGuySequenceId = -1;
+ gameSys.setAnimation(_currStonerGuySequenceId, 21, 2);
+ gameSys.insertSequence(_currStonerGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[6] = _vm->getRandom(20) + 30;
+
+ _currGroceryStoreGuySequenceId = 0x17C;
+ _nextGroceryStoreGuySequenceId = -1;
+ gameSys.setAnimation(0x17C, 20, 3);
+ gameSys.insertSequence(0x17C, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[5] = _vm->getRandom(50) + 130;
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ gameSys.insertSequence(0x17F, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x174, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ _vm->clearFlag(kGFSceneFlag1);
+ _vm->endSceneInit();
+ gameSys.setAnimation(0x182, 140, 0);
+ gameSys.insertSequence(0x182, 140, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(11, 9, kDirIdleRight);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 17:
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ break;
+ case 18:
+ gnap.initPos(11, 8, kDirBottomLeft);
+ plat.initPos(11, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1);
+ break;
+ case 21:
+ gnap.initPos(-1, 8, kDirBottomLeft);
+ plat.initPos(-1, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ break;
+ case 22:
+ gnap.initPos(7, 6, kDirBottomRight);
+ plat.initPos(8, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1);
+ break;
+ default:
+ gnap.initPos(8, 6, kDirBottomLeft);
+ plat.initPos(9, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1);
+ _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE;
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+ _vm->testWalk(0, 1, 7, 9, 8, 9);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS20Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS20Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(20);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20ExitParkingLot:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 21;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot] + Common::Point(0, 1), -1, 0x107CF, 1);
+ plat._idleFacing = kDirIdleRight;
+ }
+ break;
+
+ case kHS20ExitPhone:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 17;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS20ExitOutsideToyStore:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 18;
+ _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE;
+ }
+ break;
+
+ case kHS20ExitInsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 22;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(0, - 1), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ plat._idleFacing = kDirIdleRight;
+ }
+ break;
+
+ case kHS20ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ if (_stonerGuyShowingJoint)
+ _vm->_timers[4] = 0;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 24;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS20LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS20StonerGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20StonerGuy], 5, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2(Common::Point(5, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ if (_stonerGuyShowingJoint)
+ gnap._actionStatus = kAS20GrabJoint;
+ else
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ if (_vm->isFlag(kGFJointTaken))
+ gnap._actionStatus = kAS20TalkStonerGuyNoJoint;
+ else
+ gnap._actionStatus = kAS20TalkStonerGuyHasJoint;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20GroceryStoreGuy:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 3));
+ break;
+ case GRAB_CURSOR:
+ _stonerGuyShowingJoint = false;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20GrabGroceryStoreGuy;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20TalkGroceryStoreGuy;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20GroceryStoreHat:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemCowboyHat) {
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20SwitchGroceryStoreHat;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 1, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(1, 6));
+ break;
+ case GRAB_CURSOR:
+ _stonerGuyShowingJoint = false;
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS20GrabGroceryStoreHat;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS20WalkArea1:
+ case kHS20WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0) {
+ _vm->_hotspots[kHS20WalkArea1]._rect.bottom += 48;
+ plat.updateIdleSequence();
+ _vm->_hotspots[kHS20WalkArea1]._rect.bottom -= 48;
+ }
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->_timers[5] && _nextGroceryStoreGuySequenceId == -1) {
+ _vm->_timers[5] = _vm->getRandom(50) + 130;
+ if (_vm->getRandom(4) != 0)
+ _nextGroceryStoreGuySequenceId = 0x17C;
+ else
+ _nextGroceryStoreGuySequenceId = 0x17A;
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x183, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x184, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x185, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene20::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS20LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS20TalkStonerGuyNoJoint:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16E;
+ _vm->_timers[5] = 100;
+ _vm->_timers[6] = 100;
+ break;
+ case kAS20TalkStonerGuyHasJoint:
+ gameSys.setAnimation(0x168, 21, 2);
+ gameSys.setAnimation(379, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x168, 21, 0x170, 21, kSeqSyncWait, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x168;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16B;
+ _vm->_timers[5] = 200;
+ _vm->_timers[6] = 200;
+ _vm->_timers[4] = 100;
+ _stonerGuyShowingJoint = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS20GrabJoint:
+ _nextStonerGuySequenceId = 0x16A;
+ break;
+ case kAS20ActionDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS20TalkGroceryStoreGuy:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _groceryStoreGuyCtr = (_groceryStoreGuyCtr + 1) % 2;
+ if (_groceryStoreGuyCtr != 0)
+ _nextGroceryStoreGuySequenceId = 0x176;
+ else
+ _nextGroceryStoreGuySequenceId = 0x177;
+ _vm->_timers[5] = 100;
+ _vm->_timers[6] = 100;
+ break;
+ case kAS20GrabGroceryStoreGuy:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _vm->_timers[5] = 120;
+ _vm->_timers[6] = 120;
+ _nextGroceryStoreGuySequenceId = 0x178;
+ break;
+ case kAS20GrabGroceryStoreHat:
+ gameSys.setAnimation(0x170, 21, 2);
+ gameSys.setAnimation(0x17B, 20, 3);
+ gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0);
+ _vm->stopSound(0x1A1);
+ stopSounds();
+ _currGroceryStoreGuySequenceId = 0x17B;
+ _currStonerGuySequenceId = 0x170;
+ _nextGroceryStoreGuySequenceId = 0x179;
+ break;
+ case kAS20SwitchGroceryStoreHat:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x180, gnap._id, 0);
+ gameSys.insertSequence(0x180, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x180;
+ gnap._sequenceDatNum = 0;
+ _vm->invRemove(kItemCowboyHat);
+ _vm->invAdd(kItemGroceryStoreHat);
+ gnap._actionStatus = kAS20SwitchGroceryStoreHatDone;
+ break;
+ case kAS20SwitchGroceryStoreHatDone:
+ gameSys.insertSequence(0x17F, 20, 372, 20, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFGroceryStoreHatTaken);
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0x12C, 255);
+ gameSys.setAnimation(0x181, 256, 0);
+ gameSys.insertSequence(0x181, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ _vm->setGrabCursorSprite(kItemGroceryStoreHat);
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(Common::Point(3, 8), -1, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS20GrabJointDone:
+ _vm->setGrabCursorSprite(kItemJoint);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextGroceryStoreGuySequenceId) {
+ case 0x176:
+ case 0x177:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = 0x16D;
+ break;
+ case 0x178:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.setAnimation(0x17D, gnap._id, 0);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x17D;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS20ActionDone;
+ gameSys.setAnimation(0x16D, 21, 2);
+ gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16D;
+ _currGroceryStoreGuySequenceId = 0x178;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ break;
+ case 0x179:
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.setAnimation(0x16D, 21, 0);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x17E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x17E;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS20ActionDone;
+ gameSys.setAnimation(0x16D, 21, 2);
+ gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currStonerGuySequenceId = 0x16D;
+ _currGroceryStoreGuySequenceId = 377;
+ _nextGroceryStoreGuySequenceId = -1;
+ _nextStonerGuySequenceId = -1;
+ gnap.walkTo(Common::Point(4, 8), -1, 0x107BB, 1);
+ break;
+ case 0x17C:
+ gameSys.setAnimation(0, 0, 3);
+ _nextStonerGuySequenceId = 0x171;
+ break;
+ case 0x17A:
+ gameSys.setAnimation(0, 0, 3);
+ _nextStonerGuySequenceId = 0x16F;
+ break;
+ case 0x175:
+ gameSys.setAnimation(0x175, 20, 0);
+ gameSys.setAnimation(0x175, 20, 3);
+ gameSys.insertSequence(0x175, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = 0x175;
+ _nextGroceryStoreGuySequenceId = -1;
+ gnap._actionStatus = kAS20ActionDone;
+ break;
+ default:
+ if (_nextGroceryStoreGuySequenceId != -1) {
+ gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3);
+ gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId;
+ _nextGroceryStoreGuySequenceId = -1;
+ }
+ break;
+ }
+ }
+
+ updateAnimationsCb();
+}
+
+/*****************************************************************************/
+
+Scene21::Scene21(GnapEngine *vm) : Scene(vm) {
+ _currOldLadySequenceId = -1;
+ _nextOldLadySequenceId = -1;
+}
+
+int Scene21::init() {
+ _vm->_gameSys->setAnimation(0, 0, 3);
+
+ return _vm->isFlag(kGFTwigTaken) ? 0x94 : 0x93;
+}
+
+void Scene21::updateHotspots() {
+ _vm->setHotspot(kHS21Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS21Banana, 94, 394, 146, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 6);
+ _vm->setHotspot(kHS21OldLady, 402, 220, 528, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS21ExitOutsideGrubCity, 522, 498, 800, 600, SF_EXIT_SE_CURSOR | SF_WALKABLE, 5, 10);
+ _vm->setHotspot(kHS21WalkArea1, 0, 0, 800, 440);
+ _vm->setHotspot(kHS21WalkArea2, 698, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS21Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk04) || !_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS21Banana]._flags = SF_WALKABLE | SF_DISABLED;
+ if (_vm->isFlag(kGFTwigTaken))
+ _vm->_hotspots[kHS21OldLady]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene21::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(6);
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFTwigTaken)) {
+ if (_vm->isFlag(kGFKeysTaken)) {
+ gnap.initPos(5, 8, kDirBottomRight);
+ plat.initPos(6, 8, kDirIdleLeft);
+ gameSys.insertSequence(0x8E, 2, 0, 0, kSeqNone, 0, 0, 0);
+ if (!_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->clearFlag(kGFKeysTaken);
+ } else {
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ if (!_vm->isFlag(kGFUnk04))
+ gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+ } else {
+ gnap.initPos(5, 11, kDirBottomRight);
+ plat.initPos(6, 11, kDirIdleLeft);
+ _currOldLadySequenceId = 0x89;
+ gameSys.setAnimation(0x89, 79, 3);
+ gameSys.insertSequence(_currOldLadySequenceId, 79, 0, 0, kSeqNone, 0, 0, 0);
+ _nextOldLadySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS21Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS21Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21Banana:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 5));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS21Banana]) | 0x10000, 1);
+ gnap.playPullOutDevice(Common::Point(2, 5));
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS21GrabBanana;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21OldLady:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemGroceryStoreHat) {
+ _vm->_newSceneNum = 47;
+ gnap.walkTo(Common::Point(4, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21UseHatWithOldLady;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 6), 7, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ _vm->_hotspots[kHS21WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21GrabOldLady;
+ _vm->_hotspots[kHS21WalkArea1]._flags &= ~SF_WALKABLE;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS21OldLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS21TalkOldLady;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS21ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity], 0, 0x107B3, 1);
+ gnap._actionStatus = kAS21LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS21WalkArea1:
+ case kHS21WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->isFlag(kGFTwigTaken) && !_vm->_timers[4] && _nextOldLadySequenceId == -1 && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextOldLadySequenceId = 0x88;
+ break;
+ case 1:
+ _nextOldLadySequenceId = 0x8A;
+ break;
+ default:
+ _nextOldLadySequenceId = 0x89;
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 100;
+ gameSys.insertSequence(0x92, 255, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene21::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS21TalkOldLady:
+ _nextOldLadySequenceId = 0x8B;
+ gnap._actionStatus = -1;
+ break;
+ case kAS21GrabBanana:
+ gameSys.setAnimation(0x8C, 59, 0);
+ gameSys.insertSequence(0x8C, 59, 141, 59, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFUnk04);
+ _vm->invAdd(kItemBanana);
+ updateHotspots();
+ gnap._actionStatus = kAS21GrabBananaDone;
+ break;
+ case kAS21GrabBananaDone:
+ _vm->setGrabCursorSprite(kItemBanana);
+ gnap._actionStatus = -1;
+ break;
+ case kAS21GrabOldLady:
+ _vm->_timers[4] = _vm->getRandom(30) + 50;
+ _nextOldLadySequenceId = 0x87;
+ break;
+ case kAS21UseHatWithOldLady:
+ gameSys.setAnimation(0x8F, gnap._id, 0);
+ gameSys.insertSequence(0x8F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x8F;
+ gnap._actionStatus = kAS21UseHatWithOldLadyDone;
+ _vm->invAdd(kItemTickets);
+ _vm->invRemove(kItemGroceryStoreHat);
+ _vm->setGrabCursorSprite(-1);
+ break;
+ case kAS21UseHatWithOldLadyDone:
+ _nextOldLadySequenceId = 0x91;
+ break;
+ case kAS21LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextOldLadySequenceId != -1) {
+ if (_nextOldLadySequenceId == 0x87) {
+ gameSys.setAnimation(_nextOldLadySequenceId, 79, 3);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x86, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x86;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = -1;
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ } else if (_nextOldLadySequenceId == 0x91) {
+ gameSys.setAnimation(0x91, 79, 0);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS21LeaveScene;
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ } else {
+ gameSys.setAnimation(_nextOldLadySequenceId, 79, 3);
+ gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0);
+ _currOldLadySequenceId = _nextOldLadySequenceId;
+ _nextOldLadySequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene22::Scene22(GnapEngine *vm) : Scene(vm) {
+ _caughtBefore = false;
+ _cashierCtr = 3;
+ _nextCashierSequenceId = -1;
+ _currCashierSequenceId = -1;
+}
+
+int Scene22::init() {
+ return 0x5E;
+}
+
+void Scene22::updateHotspots() {
+ _vm->setHotspot(kHS22Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS22ExitOutsideGrubCity, 0, 180, 184, 472, SF_EXIT_L_CURSOR, 3, 6);
+ _vm->setHotspot(kHS22ExitBackGrubCity, 785, 405, 800, 585, SF_EXIT_R_CURSOR, 11, 9);
+ _vm->setHotspot(kHS22Cashier, 578, 230, 660, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS22WalkArea1, 553, 0, 800, 542);
+ _vm->setHotspot(kHS22WalkArea2, 0, 0, 552, 488);
+ _vm->setDeviceHotspot(kHS22Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene22::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ gameSys.insertSequence(0x5D, 254, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currCashierSequenceId = 0x59;
+ _nextCashierSequenceId = -1;
+
+ gameSys.setAnimation(0x59, 1, 3);
+ gameSys.insertSequence(_currCashierSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(2, 8, kDirBottomRight);
+ plat.initPos(1, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y, kDirBottomRight);
+ plat.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y + 1, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1);
+ }
+
+ if (_vm->isFlag(kGFSceneFlag1)) {
+ int storeDetectiveSeqId;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemCereals);
+ if (_caughtBefore) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ storeDetectiveSeqId = 0x55;
+ break;
+ case 1:
+ storeDetectiveSeqId = 0x56;
+ break;
+ default:
+ storeDetectiveSeqId = 0x57;
+ break;
+ }
+ } else {
+ _caughtBefore = true;
+ storeDetectiveSeqId = 0x54;
+ }
+ gameSys.waitForUpdate();
+ gameSys.requestClear1();
+ gameSys.drawSpriteToBackground(0, 0, 0x44);
+ gameSys.setAnimation(storeDetectiveSeqId, 256, 4);
+ gameSys.insertSequence(storeDetectiveSeqId, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 20;
+ _caughtBefore = true;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS22Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS22Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS22ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS22LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS22ExitBackGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 23;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS22LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS22Cashier:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS22Cashier], 8, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 4));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS22Cashier], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS22TalkCashier;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS22WalkArea1:
+ case kHS22WalkArea2:
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[6] && _nextCashierSequenceId == -1) {
+ _vm->_timers[6] = _vm->getRandom(30) + 20;
+ if (_vm->getRandom(8) != 0) {
+ _nextCashierSequenceId = 0x59;
+ } else {
+ _cashierCtr = (_cashierCtr + 1) % 3;
+ switch (_cashierCtr) {
+ case 1:
+ _nextCashierSequenceId = 0x58;
+ break;
+ case 2:
+ _nextCashierSequenceId = 0x5A;
+ break;
+ case 3:
+ _nextCashierSequenceId = 0x5B;
+ break;
+ default:
+ _nextCashierSequenceId = 0x58;
+ break;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = 400;
+ _vm->_timers[1] = _vm->getRandom(20) + 30;
+ _vm->_timers[0] = _vm->getRandom(75) + 75;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene22::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS22LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS22TalkCashier:
+ _nextCashierSequenceId = 0x5C;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextCashierSequenceId != -1) {
+ gameSys.setAnimation(_nextCashierSequenceId, 1, 3);
+ gameSys.insertSequence(_nextCashierSequenceId, 1, _currCashierSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currCashierSequenceId = _nextCashierSequenceId;
+ _nextCashierSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene23::Scene23(GnapEngine *vm) : Scene(vm) {
+ _currStoreClerkSequenceId = -1;
+ _nextStoreClerkSequenceId = -1;
+}
+
+int Scene23::init() {
+ return 0xC0;
+}
+
+void Scene23::updateHotspots() {
+ _vm->setHotspot(kHS23Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS23ExitFrontGrubCity, 0, 250, 15, 550, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7);
+ _vm->setHotspot(kHS23Cereals, 366, 332, 414, 408, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7);
+ _vm->setHotspot(kHS23WalkArea1, 0, 0, 340, 460);
+ _vm->setHotspot(kHS23WalkArea2, 340, 0, 800, 501);
+ _vm->setDeviceHotspot(kHS23Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 6;
+}
+
+void Scene23::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+
+ _currStoreClerkSequenceId = 0xB4;
+ _nextStoreClerkSequenceId = -1;
+
+ gameSys.setAnimation(0xB4, 1, 4);
+ gameSys.insertSequence(_currStoreClerkSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->queueInsertDeviceIcon();
+
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 7, kDirIdleLeft);
+ gameSys.insertSequence(0xBD, 255, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0xBF, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+
+ if (_vm->isFlag(kGFUnk24)) {
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ } else {
+ gnap.walkTo(Common::Point(2, 7), 0, 0x107B9, 1);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->playSequences(0x48, 0xBA, 0xBB, 0xBC);
+ _vm->setFlag(kGFUnk24);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 3, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS23Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS23Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS23Cereals:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS23Cereals], 5, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playMoan2();
+ else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS23LookCereals;
+ }
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFSceneFlag1))
+ gnap.playImpossible();
+ else {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ _vm->setFlag(kGFSceneFlag1);
+ gnap._actionStatus = kAS23GrabCereals;
+ _vm->invAdd(kItemCereals);
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS23ExitFrontGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 22;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS23LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity] + Common::Point(0, -1), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS23WalkArea1:
+ case kHS23WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(100) + 200;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ gameSys.insertSequence(0xB7, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0xB8, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ case 3:
+ gameSys.insertSequence(0xB9, 256, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(100) + 200;
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _vm->playSound(0xCE, false);
+ break;
+ case 1:
+ _vm->playSound(0xD0, false);
+ break;
+ case 2:
+ _vm->playSound(0xCF, false);
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene23::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS23LookCereals:
+ _vm->showFullScreenSprite(0x48);
+ gnap._actionStatus = -1;
+ break;
+ case kAS23GrabCereals:
+ gameSys.setAnimation(0xBE, gnap._id, 0);
+ gameSys.insertSequence(0xBE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.requestRemoveSequence(0xBF, 2);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0xBE;
+ gnap._actionStatus = kAS23GrabCerealsDone;
+ break;
+ case kAS23GrabCerealsDone:
+ _vm->setGrabCursorSprite(kItemCereals);
+ gnap._actionStatus = -1;
+ break;
+ case kAS23LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextStoreClerkSequenceId == -1) {
+ switch (_vm->getRandom(8)) {
+ case 0:
+ case 1:
+ case 2:
+ _nextStoreClerkSequenceId = 0xB4;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ _nextStoreClerkSequenceId = 0xB5;
+ break;
+ default:
+ _nextStoreClerkSequenceId = 0xB6;
+ break;
+ }
+ gameSys.setAnimation(_nextStoreClerkSequenceId, 1, 4);
+ gameSys.insertSequence(_nextStoreClerkSequenceId, 1, _currStoreClerkSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ _currStoreClerkSequenceId = _nextStoreClerkSequenceId;
+ _nextStoreClerkSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene24::Scene24(GnapEngine *vm) : Scene(vm) {
+ _currWomanSequenceId = -1;
+ _nextWomanSequenceId = -1;
+ _boySequenceId = -1;
+ _girlSequenceId = -1;
+}
+
+int Scene24::init() {
+ return 0x3B;
+}
+
+void Scene24::updateHotspots() {
+ _vm->setHotspot(kHS24Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS24ExitCircusWorld, 785, 128, 800, 600, SF_EXIT_R_CURSOR, 8, 7);
+ _vm->setHotspot(kHS24ExitOutsideGrubCity, 0, 213, 91, 600, SF_EXIT_NW_CURSOR, 1, 8);
+ _vm->setHotspot(kHS24WalkArea1, 0, 0, 0, 0);
+ _vm->setHotspot(kHS24WalkArea2, 530, 0, 800, 600);
+ _vm->setHotspot(kHS24WalkArea3, 0, 0, 800, 517);
+ _vm->setDeviceHotspot(kHS24Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene24::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ int counter = 0;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(9);
+
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+
+ gameSys.insertSequence(0x2F, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ _vm->_timers[5] = _vm->getRandom(20) + 40;
+ _vm->_timers[6] = _vm->getRandom(50) + 30;
+
+ gameSys.insertSequence(0x36, 20, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x30, 20, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x35, 20, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currWomanSequenceId = 0x35;
+ _girlSequenceId = 0x36;
+ _boySequenceId = 0x30;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 20) {
+ gnap.initPos(1, 8, kDirBottomRight);
+ plat.initPos(2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(1, 9), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(8, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+
+ case kHS24Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS24Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS24ExitCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 25;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS24LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS24ExitOutsideGrubCity:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 20;
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS24LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS24WalkArea1:
+ case kHS24WalkArea2:
+ case kHS24WalkArea3:
+ if (gnap._actionStatus == -1)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x10940))
+ _vm->playSound(0x10940, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ gameSys.insertSequence(0x37, 20, _girlSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _girlSequenceId = 0x37;
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 40;
+ gameSys.insertSequence(0x31, 20, _boySequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _boySequenceId = 0x31;
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(50) + 30;
+ counter = (counter + 1) % 3;
+ switch (counter) {
+ case 0:
+ _nextWomanSequenceId = 0x32;
+ break;
+ case 1:
+ _nextWomanSequenceId = 0x33;
+ break;
+ case 2:
+ _nextWomanSequenceId = 0x34;
+ break;
+ }
+ gameSys.insertSequence(_nextWomanSequenceId, 20, _currWomanSequenceId, 20, kSeqSyncWait, 0, 0, 0);
+ _currWomanSequenceId = _nextWomanSequenceId;
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 100;
+ switch (_vm->getRandom(3)) {
+ case 0:
+ gameSys.insertSequence(0x38, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 1:
+ gameSys.insertSequence(0x39, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ case 2:
+ gameSys.insertSequence(0x3A, 253, 0, 0, kSeqNone, 0, 0, 0);
+ break;
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene24::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS24LeaveScene)
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene25::Scene25(GnapEngine *vm) : Scene(vm) {
+ _currTicketVendorSequenceId = -1;
+ _nextTicketVendorSequenceId = -1;
+}
+
+int Scene25::init() {
+ return 0x62;
+}
+
+void Scene25::updateHotspots() {
+ _vm->setHotspot(kHS25Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS25TicketVendor, 416, 94, 574, 324, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 5);
+ _vm->setHotspot(kHS25ExitOutsideCircusWorld, 0, 519, 205, 600, SF_EXIT_SW_CURSOR, 5, 10);
+ _vm->setHotspot(kHS25ExitInsideCircusWorld, 321, 70, 388, 350, SF_EXIT_NE_CURSOR, 3, 6);
+ _vm->setHotspot(kHS25Posters1, 0, 170, 106, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS25Posters2, 146, 192, 254, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7);
+ _vm->setHotspot(kHS25Posters3, 606, 162, 654, 368, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 7);
+ _vm->setHotspot(kHS25Posters4, 708, 114, 754, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS25WalkArea1, 0, 0, 800, 439);
+ _vm->setHotspot(kHS25WalkArea2, 585, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS25Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene25::playAnims(int index) {
+ if (index > 4)
+ return;
+
+ GameSys& gameSys = *_vm->_gameSys;
+
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ switch (index) {
+ case 1:
+ _vm->_largeSprite = gameSys.createSurface(0x25);
+ break;
+ case 2:
+ _vm->_largeSprite = gameSys.createSurface(0x26);
+ break;
+ case 3:
+ _vm->_largeSprite = gameSys.createSurface(0x27);
+ break;
+ case 4:
+ _vm->_largeSprite = gameSys.createSurface(0x28);
+ break;
+ }
+ gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300);
+ _vm->delayTicksCursor(5);
+ while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) && !_vm->isKeyStatus1(Common::KEYCODE_SPACE) &&
+ !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ }
+ _vm->_mouseClickState._left = false;
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300);
+ _vm->delayTicksCursor(5);
+ _vm->deleteSurface(&_vm->_largeSprite);
+ _vm->showCursor();
+}
+
+void Scene25::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x10940, true);
+ _vm->startSoundTimerA(5);
+
+ _currTicketVendorSequenceId = 0x52;
+ gameSys.setAnimation(0x52, 39, 3);
+ gameSys.insertSequence(_currTicketVendorSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _nextTicketVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->_prevSceneNum == 24) {
+ gnap.initPos(5, 11, kDirUpLeft);
+ plat.initPos(6, 11, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 7), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 7), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(5, 6, kDirBottomRight);
+ plat.initPos(6, 6, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS25Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS25Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25TicketVendor:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemTickets) {
+ gnap._actionStatus = kAS25ShowTicketToVendor;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSIdle, Common::Point(9, 4)) | 0x10000, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS25TicketVendor], 6, 1);
+ _nextTicketVendorSequenceId = 0x5B;
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 1));
+ _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x59 : 0x56;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS25TalkTicketVendor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 24;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld], 0, 0x107B4, 1);
+ gnap._actionStatus = kAS25LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS25ExitInsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFNeedleTaken)) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld], 0, 0x107B1, 1);
+ gnap._actionStatus = kAS25LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1);
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ } else {
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(4, 5), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS25EnterCircusWihoutTicket;
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ }
+ }
+ break;
+
+ case kHS25Posters1:
+ case kHS25Posters2:
+ case kHS25Posters3:
+ case kHS25Posters4:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], -1, -1, 1);
+ if (_vm->_sceneClickedHotspot == 5 || _vm->_sceneClickedHotspot == 6)
+ gnap._idleFacing = kDirUpLeft;
+ else if (_vm->_sceneClickedHotspot == 8)
+ gnap._idleFacing = kDirBottomRight;
+ else
+ gnap._idleFacing = kDirUpRight;
+ gnap.playIdle();
+ playAnims(8 - _vm->_sceneClickedHotspot + 1);
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playMoan2();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS25WalkArea1:
+ case kHS25WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && _nextTicketVendorSequenceId == -1 && gnap._actionStatus == -1) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ switch (_vm->getRandom(13)) {
+ case 0:
+ _nextTicketVendorSequenceId = 0x54;
+ break;
+ case 1:
+ _nextTicketVendorSequenceId = 0x58;
+ break;
+ case 2:
+ _nextTicketVendorSequenceId = 0x55;
+ break;
+ case 3:
+ _nextTicketVendorSequenceId = 0x5A;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ _nextTicketVendorSequenceId = 0x5B;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ _nextTicketVendorSequenceId = 0x5C;
+ break;
+ case 12:
+ _nextTicketVendorSequenceId = 0x5D;
+ break;
+ default:
+ _nextTicketVendorSequenceId = 0x52;
+ break;
+ }
+ }
+ _vm->playSoundA();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene25::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS25TalkTicketVendor:
+ _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x57 : 0x5F;
+ gnap._actionStatus = -1;
+ break;
+ case kAS25EnterCircusWihoutTicket:
+ _nextTicketVendorSequenceId = 0x5E;
+ gameSys.setAnimation(0x5E, 39, 0);
+ gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3);
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncExists, 0, 0, 0);
+ gameSys.insertSequence(0x60, 2, 0, 0, kSeqNone, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE;
+ gnap.playIdle();
+ gnap.walkTo(_vm->_hotspotsWalkPos[3], -1, 0x107BB, 1);
+ _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS25EnterCircusWihoutTicketDone;
+ break;
+ case kAS25EnterCircusWihoutTicketDone:
+ gnap._actionStatus = -1;
+ break;
+ case kAS25ShowTicketToVendor:
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemTickets);
+ _vm->setFlag(kGFNeedleTaken);
+ gameSys.setAnimation(0x61, 40, 0);
+ gameSys.insertSequence(0x61, 40, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = kAS25ShowTicketToVendorDone;
+ break;
+ case kAS25ShowTicketToVendorDone:
+ _nextTicketVendorSequenceId = 0x53;
+ break;
+ case kAS25LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ if (_nextTicketVendorSequenceId == 0x53) {
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextTicketVendorSequenceId != -1) {
+ gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3);
+ gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currTicketVendorSequenceId = _nextTicketVendorSequenceId;
+ _nextTicketVendorSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene26::Scene26(GnapEngine *vm) : Scene(vm) {
+ _currKidSequenceId = -1;
+ _nextKidSequenceId = -1;
+}
+
+int Scene26::init() {
+ return _vm->isFlag(kGFUnk23) ? 0x61 : 0x60;
+}
+
+void Scene26::updateHotspots() {
+ _vm->setHotspot(kHS26Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS26ExitOutsideCircusWorld, 0, 590, 300, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 1, 10);
+ _vm->setHotspot(kHS26ExitOutsideClown, 200, 265, 265, 350, SF_EXIT_U_CURSOR, 3, 8);
+ _vm->setHotspot(kHS26ExitArcade, 0, 295, 150, 400, SF_EXIT_NW_CURSOR, 2, 8);
+ _vm->setHotspot(kHS26ExitElephant, 270, 290, 485, 375, SF_EXIT_U_CURSOR, 5, 8);
+ _vm->setHotspot(kHS26ExitBeerStand, 530, 290, 620, 350, SF_EXIT_NE_CURSOR, 5, 8);
+ _vm->setHotspot(kHS26WalkArea1, 0, 0, 800, 500);
+ _vm->setHotspot(kHS26WalkArea2, 281, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS26Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene26::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->startSoundTimerB(7);
+ _vm->playSound(0x1093B, true);
+
+ _currKidSequenceId = 0x5B;
+ _nextKidSequenceId = -1;
+ gameSys.setAnimation(0x5B, 160, 3);
+ gameSys.insertSequence(_currKidSequenceId, 160, 0, 0, kSeqNone, 0, 0, 0);
+
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ _vm->_timers[4] = _vm->getRandom(20) + 50;
+ _vm->_timers[6] = _vm->getRandom(50) + 100;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x58, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5C, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5D, 40, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0x5E, 40, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 25) {
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-2, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(2, 8, kDirBottomRight);
+ plat.initPos(3, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS26Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS26Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS26ExitOutsideCircusWorld:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 25;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideCircusWorld].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideClown].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitArcade:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 29;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitArcade].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitElephant:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 30;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitElephant].y), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26ExitBeerStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 31;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitBeerStand].y), 0, 0x107BB, 1);
+ gnap._actionStatus = kAS26LeaveScene;
+ }
+ break;
+
+ case kHS26WalkArea1:
+ case kHS26WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5] && _nextKidSequenceId == -1) {
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ if (_vm->getRandom(5) != 0)
+ _nextKidSequenceId = 0x5B;
+ else
+ _nextKidSequenceId = 0x5A;
+ }
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 130;
+ gameSys.insertSequence(0x59, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[6]) {
+ _vm->_timers[6] = _vm->getRandom(50) + 100;
+ gameSys.insertSequence(0x5F, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene26::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS26LeaveScene)
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextKidSequenceId != -1) {
+ gameSys.insertSequence(_nextKidSequenceId, 160, _currKidSequenceId, 160, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 160, 3);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene27::Scene27(GnapEngine *vm) : Scene(vm) {
+ _nextJanitorSequenceId = -1;
+ _currJanitorSequenceId = -1;
+}
+
+int Scene27::init() {
+ return 0xD5;
+}
+
+void Scene27::updateHotspots() {
+ _vm->setHotspot(kHS27Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS27Janitor, 488, 204, 664, 450, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 8);
+ _vm->setHotspot(kHS27Bucket, 129, 406, 186, 453, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 6);
+ _vm->setHotspot(kHS27ExitCircus, 200, 585, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS27ExitArcade, 0, 0, 15, 600, SF_EXIT_L_CURSOR, 0, 6);
+ _vm->setHotspot(kHS27ExitBeerStand, 785, 0, 800, 600, SF_EXIT_R_CURSOR, 11, 7);
+ _vm->setHotspot(kHS27ExitClown, 340, 240, 460, 420, SF_EXIT_U_CURSOR, 6, 8);
+ _vm->setHotspot(kHS27WalkArea1, 0, 0, 800, 507);
+ _vm->setDeviceHotspot(kHS27Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk13))
+ _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene27::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(4);
+ _vm->_timers[7] = _vm->getRandom(100) + 300;
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFUnk13))
+ gameSys.insertSequence(0xD3, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.insertSequence(0xCB, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currJanitorSequenceId = 0xCB;
+ _nextJanitorSequenceId = -1;
+
+ gameSys.setAnimation(0xCB, 39, 3);
+ _vm->_timers[5] = _vm->getRandom(20) + 60;
+
+ switch (_vm->_prevSceneNum) {
+ case 26:
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ break;
+ case 29:
+ gnap.initPos(-1, 8, kDirBottomRight);
+ plat.initPos(-1, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1);
+ break;
+ case 31:
+ gnap.initPos(12, 8, kDirBottomLeft);
+ plat.initPos(12, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(8, 9), -1, 0x107C2, 1);
+ break;
+ default:
+ gnap.initPos(6, 8, kDirBottomRight);
+ plat.initPos(5, 9, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->_sceneClickedHotspot = -1;
+ if (gnap._actionStatus < 0)
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS27Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS27Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27Janitor:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemPicture) {
+ gnap._idleFacing = kDirUpLeft;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, 0x107BC, 1))
+ gnap._actionStatus = kAS27ShowPictureToJanitor;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS27Janitor], 7, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 3));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS27TalkJanitor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27Bucket:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 3, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(3, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS27Bucket]) | 0x10000, 1);
+ gnap._actionStatus = kAS27GrabBucket;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS27ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitCircus] + Common::Point(1, 0), -1, 0x107C7, 1);
+ }
+ break;
+
+ case kHS27ExitArcade:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 29;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitArcade].y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitArcade] + Common::Point(0, 1), -1, 0x107CF, 1);
+ }
+ break;
+
+ case kHS27ExitBeerStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 31;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitBeerStand].y), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitBeerStand] + Common::Point(0, 1), -1, 0x107CD, 1);
+ }
+ break;
+
+ case kHS27ExitClown:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFPlatypus)) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 28;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown], 0, 0x107AD, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown] + Common::Point(1, 0), -1, 0x107C4, 1);
+ } else {
+ _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS27ExitClown].x, 7), 0, 0x107BC, 1);
+ _vm->_hotspots[kHS27WalkArea1]._flags &= SF_WALKABLE;
+ gnap._actionStatus = kAS27TryEnterClownTent;
+ }
+ }
+ break;
+
+ case kHS27WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(3) != 0)
+ _nextJanitorSequenceId = 0xCB;
+ else
+ _nextJanitorSequenceId = 0xCF;
+ }
+ }
+ if (!_vm->_timers[7]) {
+ _vm->_timers[7] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0)
+ gameSys.insertSequence(0xD4, 120, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene27::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS27TalkJanitor:
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _nextJanitorSequenceId = 0xCC;
+ break;
+ case 1:
+ _nextJanitorSequenceId = 0xCD;
+ break;
+ case 2:
+ _nextJanitorSequenceId = 0xCE;
+ break;
+ }
+ break;
+ case kAS27GrabBucket:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED;
+ _vm->invAdd(kItemEmptyBucket);
+ _vm->setFlag(kGFUnk13);
+ gameSys.setAnimation(0xD2, 39, 0);
+ gameSys.insertSequence(0xD2, 39, 211, 39, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS27GrabBucketDone;
+ break;
+ case kAS27GrabBucketDone:
+ _vm->setGrabCursorSprite(kItemEmptyBucket);
+ gnap._actionStatus = -1;
+ break;
+ case kAS27ShowPictureToJanitor:
+ _nextJanitorSequenceId = 0xD0;
+ break;
+ case kAS27TryEnterClownTent:
+ _nextJanitorSequenceId = 0xD1;
+ gameSys.insertSequence(0xD1, 39, _currJanitorSequenceId, 39, kSeqSyncExists, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ gnap._actionStatus = kAS27TryEnterClownTentDone;
+ break;
+ case kAS27TryEnterClownTentDone:
+ _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[7].x, 9), -1, 0x107BC, 1);
+ _vm->_hotspots[kHS27WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = -1;
+ break;
+ case kAS27EnterClownTent:
+ gnap.walkTo(gnap._pos, 0, 0x107B2, 1);
+ gnap._actionStatus = kAS27LeaveScene;
+ break;
+ case kAS27LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextJanitorSequenceId) {
+ case -1:
+ _nextJanitorSequenceId = 0xCB;
+ gameSys.insertSequence(0xCB, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ case 0xCC:
+ case 0xCD:
+ case 0xCE:
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ case 0xD0:
+ // Show picture to janitor
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 0);
+ gnap._actionStatus = kAS27EnterClownTent;
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ _vm->setFlag(kGFPlatypus);
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemPicture);
+ _vm->_newSceneNum = 28;
+ break;
+ default:
+ gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextJanitorSequenceId, 39, 3);
+ _currJanitorSequenceId = _nextJanitorSequenceId;
+ _nextJanitorSequenceId = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene28::Scene28(GnapEngine *vm) : Scene(vm) {
+ _currClownSequenceId = -1;
+ _nextClownSequenceId = -1;
+ _clownTalkCtr = 0;
+}
+
+int Scene28::init() {
+ return 0x125;
+}
+
+void Scene28::updateHotspots() {
+ _vm->setHotspot(kHS28Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS28Horn, 148, 352, 215, 383, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7);
+ _vm->setHotspot(kHS28Clown, 130, 250, 285, 413, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5);
+ _vm->setHotspot(kHS28ExitOutsideClown, 660, 190, 799, 400, SF_EXIT_R_CURSOR, 9, 6);
+ _vm->setHotspot(kHS28EmptyBucket, 582, 421, 643, 478, SF_WALKABLE | SF_DISABLED, 9, 7);
+ _vm->setHotspot(kHS28WalkArea1, 0, 0, 799, 523);
+ _vm->setHotspot(kHS28WalkArea2, 0, 0, 0, 0, 7, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS28Device, -1, -1, -1, -1);
+ if (_vm->invHas(kItemHorn))
+ _vm->_hotspots[kHS28Horn]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFUnk22))
+ _vm->_hotspots[kHS28EmptyBucket]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsCount = 8;
+}
+
+void Scene28::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093C, true);
+ _nextClownSequenceId = -1;
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x124, 255, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFUnk22))
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFMudTaken)) {
+ if (_vm->isFlag(kGFUnk21)) {
+ gameSys.setAnimation(0x11C, 39, 3);
+ gameSys.insertSequence(0x11C, 39, 0, 0, kSeqNone, 0, 0, 0);
+ if (!_vm->invHas(kItemHorn))
+ gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, 0, 0, 0);
+ _currClownSequenceId = 0x11C;
+ } else {
+ _currClownSequenceId = 0x11B;
+ gameSys.setAnimation(0x11B, 39, 3);
+ gameSys.insertSequence(_currClownSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ }
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ } else {
+ gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.initPos(8, 8, kDirBottomLeft);
+ plat.initPos(9, 8, kDirIdleRight);
+ _vm->endSceneInit();
+ _vm->playSequences(0xF7, 0x121, 0x122, 0x123);
+ _currClownSequenceId = 0x115;
+ _vm->setFlag(kGFMudTaken);
+ gameSys.setAnimation(0x115, 39, 3);
+ gameSys.insertSequence(_currClownSequenceId, 39, 0x11B, 39, kSeqSyncWait, 0, 0, 0);
+ _nextClownSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ gnap._actionStatus = kAS28GnapWaiting;
+ while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ _vm->updateMouseCursor();
+ }
+ gnap._actionStatus = -1;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS28Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS28Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28Horn:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(2, 8), 3, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 4));
+ break;
+ case GRAB_CURSOR:
+ if (_vm->isFlag(kGFUnk21)) {
+ if (!_vm->invHas(kItemHorn)) {
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28Horn]) | 0x10000, 1);
+ gnap._actionStatus = kAS28GrabHornSuccess;
+ }
+ } else {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(2, 8), 0, 0x107BB, 1);
+ _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Horn], 0, 0x107BB, 1);
+ _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS28GrabHornFails;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28Clown:
+ if (gnap._actionStatus < 0) {
+ if (_vm->isFlag(kGFUnk21)) {
+ if (_vm->_verbCursor == LOOK_CURSOR)
+ gnap.playScratchingHead(Common::Point(5, 2));
+ else
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithBeer) {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS28UseBeerBucketWithClown;
+ } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithPill) {
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1);
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gnap._actionStatus = kAS28UsePillBucketWithClown;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS28Clown], 2, 4);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 2));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS28TalkClown;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown], 0, 0x107BF, 1);
+ gnap._actionStatus = kAS28LeaveScene;
+ _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown] + Common::Point(-1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS28EmptyBucket:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 6);
+ } else if (_vm->isFlag(kGFUnk21)) {
+ gnap.playImpossible(Common::Point(8, 6));
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 6));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28EmptyBucket]) | 0x10000, 1);
+ gnap._actionStatus = kAS28GrabEmptyBucket;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS28WalkArea1:
+ case kHS28WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093C))
+ _vm->playSound(0x1093C, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 80;
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFUnk21))
+ _nextClownSequenceId = 0x114;
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene28::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS28UseBeerBucketWithClown:
+ _vm->setFlag(kGFUnk22);
+ _nextClownSequenceId = 0x113;
+ _vm->invRemove(kItemBucketWithBeer);
+ updateHotspots();
+ break;
+ case kAS28UsePillBucketWithClown:
+ _nextClownSequenceId = 0x116;
+ _vm->invRemove(kItemBucketWithPill);
+ _vm->setFlag(kGFUnk22);
+ _vm->setFlag(kGFUnk21);
+ updateHotspots();
+ break;
+ case kAS28GrabHornFails:
+ _nextClownSequenceId = 0x119;
+ break;
+ case kAS28GrabHornSuccess:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x117, 59, 0);
+ gameSys.insertSequence(0x117, 59, 280, 59, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS28GrabHornSuccessDone;
+ break;
+ case kAS28GrabHornSuccessDone:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0xF6, 255);
+ gameSys.setAnimation(0x120, 256, 0);
+ gameSys.insertSequence(0x120, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ _vm->setGrabCursorSprite(kItemHorn);
+ _vm->invAdd(kItemHorn);
+ updateHotspots();
+ gnap._actionStatus = -1;
+ break;
+ case kAS28GrabEmptyBucket:
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.setAnimation(0x111, 99, 0);
+ gameSys.insertSequence(0x111, 99, 274, 99, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS28GrabEmptyBucketDone;
+ break;
+ case kAS28GrabEmptyBucketDone:
+ _vm->setGrabCursorSprite(kItemEmptyBucket);
+ _vm->clearFlag(kGFUnk22);
+ updateHotspots();
+ _vm->invAdd(kItemEmptyBucket);
+ gnap._actionStatus = -1;
+ break;
+ case kAS28GrabHornFailsDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 281, 39, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _currClownSequenceId = 0x11B;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = -1;
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107BB, 1);
+ break;
+ case kAS28TalkClown:
+ // The original was only using the first two sequences,
+ // due to a bug.
+ _clownTalkCtr = (_clownTalkCtr + 1) % 3;
+ if (_clownTalkCtr == 0)
+ _nextClownSequenceId = 0x11D;
+ else if (_clownTalkCtr == 1)
+ _nextClownSequenceId = 0x11E;
+ else if (_clownTalkCtr == 2)
+ _nextClownSequenceId = 0x11F;
+ break;
+ case kAS28GnapWaiting:
+ gnap._actionStatus = -1;
+ break;
+ case kAS28LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextClownSequenceId) {
+ case 0x113:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x11B, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClownSequenceId = 0x11B;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = kAS28GnapWaiting;
+ break;
+ case 0x116:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x11C, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0);
+ _currClownSequenceId = _nextClownSequenceId;
+ _nextClownSequenceId = -1;
+ gnap._actionStatus = kAS28GnapWaiting;
+ break;
+ case 0x11D:
+ case 0x11E:
+ case 0x11F:
+ gnap._actionStatus = -1;
+ break;
+ case 0x119:
+ gameSys.insertSequence(_nextClownSequenceId, 39, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 0);
+ gameSys.removeSequence(_currClownSequenceId, 39, true);
+ gnap._actionStatus = kAS28GrabHornFailsDone;
+ gnap._sequenceId = _nextClownSequenceId;
+ gnap._sequenceDatNum = 0;
+ _nextClownSequenceId = -1;
+ break;
+ }
+ if (_nextClownSequenceId != -1) {
+ gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClownSequenceId, 39, 3);
+ _currClownSequenceId = _nextClownSequenceId;
+ _nextClownSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene29::Scene29(GnapEngine *vm) : Scene(vm) {
+ _currMonkeySequenceId = -1;
+ _nextMonkeySequenceId = -1;
+ _currManSequenceId = -1;
+ _nextManSequenceId = -1;
+}
+
+int Scene29::init() {
+ return 0xF6;
+}
+
+void Scene29::updateHotspots() {
+ _vm->setHotspot(kHS29Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS29Monkey, 410, 374, 518, 516, SF_WALKABLE | SF_DISABLED, 3, 7);
+ _vm->setHotspot(kHS29ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS29ExitOutsideClown, 785, 0, 800, 600, SF_EXIT_R_CURSOR | SF_WALKABLE, 11, 9);
+ _vm->setHotspot(kHS29Arcade, 88, 293, 155, 384, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS29WalkArea1, 0, 0, 800, 478);
+ _vm->setDeviceHotspot(kHS29Device, -1, -1, -1, -1);
+ if (_vm->invHas(kItemHorn))
+ _vm->_hotspots[kHS29Monkey]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene29::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->invHas(kItemHorn)) {
+ _currMonkeySequenceId = 0xE8;
+ _nextMonkeySequenceId = -1;
+ gameSys.setAnimation(0xE8, 159, 4);
+ gameSys.insertSequence(_currMonkeySequenceId, 159, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0);
+ _currManSequenceId = 0xED;
+ _nextManSequenceId = -1;
+ gameSys.setAnimation(0xED, 39, 3);
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ } else {
+ gameSys.insertSequence(0xF4, 19, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0, 0, 4);
+ gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0, 0, 3);
+ }
+
+ gameSys.insertSequence(0xF3, 39, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0xF5, 38, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 27) {
+ gnap.initPos(12, 7, kDirBottomRight);
+ plat.initPos(12, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1);
+ } else {
+ gnap.initPos(-1, 7, kDirBottomRight);
+ plat.initPos(-2, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS29Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS29Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29Monkey:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemBanana) {
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Monkey], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS29UseBananaWithMonkey;
+ _vm->_newSceneNum = 51;
+ _vm->_isLeavingScene = true;
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Monkey], 5, 6);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 6));
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(_vm->_hotspotsWalkPos[kHS29Monkey]);
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS29LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus] + Common::Point(1, 0), -1, -1, 1);
+ }
+ break;
+
+ case kHS29ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS29LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown] + Common::Point(0, -1), -1, 0x107CD, 1);
+ }
+ break;
+
+ case kHS29Arcade:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ _vm->setGrabCursorSprite(-1);
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 52;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Arcade], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[kHS29Arcade]);
+ gnap._actionStatus = kAS29LeaveScene;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Arcade], 2, 3);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan2();
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS29WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (gnap._actionStatus < 0) {
+ gnap.updateIdleSequence();
+ plat.updateIdleSequence();
+ }
+ if (!_vm->_timers[4]) {
+ if (_vm->invHas(kItemHorn)) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextManSequenceId = 0xED;
+ break;
+ case 1:
+ _nextManSequenceId = 0xEE;
+ break;
+ case 2:
+ _nextManSequenceId = 0xEF;
+ break;
+ case 3:
+ _nextManSequenceId = 0xF0;
+ break;
+ case 4:
+ _nextManSequenceId = 0xF1;
+ break;
+ }
+ }
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene29::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS29UseBananaWithMonkey:
+ _nextMonkeySequenceId = 0xE5;
+ break;
+ case kAS29LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextManSequenceId != -1) {
+ gameSys.insertSequence(_nextManSequenceId, 39, _currManSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextManSequenceId, 39, 3);
+ _currManSequenceId = _nextManSequenceId;
+ _nextManSequenceId = -1;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ if (_nextMonkeySequenceId == 0xE5) {
+ gameSys.insertSequence(0xF2, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0xF2;
+ gameSys.setAnimation(0xE6, 159, 0);
+ gameSys.setAnimation(0, 159, 4);
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xE6, 159, _nextMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = kAS29LeaveScene;
+ _currMonkeySequenceId = 0xE6;
+ _nextMonkeySequenceId = -1;
+ _vm->_timers[5] = 30;
+ while (_vm->_timers[5] && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+
+ _vm->_plat->walkTo(Common::Point(0, 8), 1, 0x107CF, 1);
+
+ while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ } else if (_nextMonkeySequenceId == -1) {
+ switch (_vm->getRandom(6)) {
+ case 0:
+ _nextMonkeySequenceId = 0xE8;
+ break;
+ case 1:
+ _nextMonkeySequenceId = 0xE9;
+ break;
+ case 2:
+ _nextMonkeySequenceId = 0xEA;
+ break;
+ case 3:
+ _nextMonkeySequenceId = 0xEB;
+ break;
+ case 4:
+ _nextMonkeySequenceId = 0xEC;
+ break;
+ case 5:
+ _nextMonkeySequenceId = 0xE7;
+ break;
+ }
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextMonkeySequenceId, 159, 4);
+ _currMonkeySequenceId = _nextMonkeySequenceId;
+ _nextMonkeySequenceId = -1;
+ } else {
+ gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextMonkeySequenceId, 159, 4);
+ _currMonkeySequenceId = _nextMonkeySequenceId;
+ _nextMonkeySequenceId = -1;
+ }
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group2.h b/engines/gnap/scenes/group2.h
new file mode 100644
index 0000000000..8f56594f16
--- /dev/null
+++ b/engines/gnap/scenes/group2.h
@@ -0,0 +1,407 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GROUP2_H
+#define GNAP_GROUP2_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS20Platypus = 0,
+ kHS20GroceryStoreHat = 1,
+ kHS20ExitParkingLot = 2,
+ kHS20StonerGuy = 3,
+ kHS20GroceryStoreGuy = 4,
+ kHS20Device = 5,
+ kHS20ExitInsideGrubCity = 6,
+ kHS20ExitOutsideCircusWorld = 7,
+ kHS20ExitOutsideToyStore = 8,
+ kHS20ExitPhone = 9,
+ kHS20WalkArea1 = 10,
+ kHS20WalkArea2 = 11
+};
+
+enum {
+ kHS21Platypus = 0,
+ kHS21Banana = 1,
+ kHS21OldLady = 2,
+ kHS21Device = 3,
+ kHS21ExitOutsideGrubCity = 4,
+ kHS21WalkArea1 = 5,
+ kHS21WalkArea2 = 6
+};
+
+enum {
+ kHS22Platypus = 0,
+ kHS22ExitOutsideGrubCity = 1,
+ kHS22ExitBackGrubCity = 2,
+ kHS22Cashier = 3,
+ kHS22Device = 4,
+ kHS22WalkArea1 = 5,
+ kHS22WalkArea2 = 6
+};
+
+enum {
+ kHS23Platypus = 0,
+ kHS23ExitFrontGrubCity = 1,
+ kHS23Device = 2,
+ kHS23Cereals = 3,
+ kHS23WalkArea1 = 4,
+ kHS23WalkArea2 = 5
+};
+
+enum {
+ kHS24Platypus = 0,
+ kHS24ExitCircusWorld = 1,
+ kHS24ExitOutsideGrubCity = 2,
+ kHS24Device = 3,
+ kHS24WalkArea1 = 4,
+ kHS24WalkArea2 = 5,
+ kHS24WalkArea3 = 6
+};
+
+enum {
+ kHS25Platypus = 0,
+ kHS25TicketVendor = 1,
+ kHS25ExitOutsideCircusWorld = 2,
+ kHS25ExitInsideCircusWorld = 3,
+ kHS25Device = 4,
+ kHS25Posters1 = 5,
+ kHS25Posters2 = 6,
+ kHS25Posters3 = 7,
+ kHS25Posters4 = 8,
+ kHS25WalkArea1 = 9,
+ kHS25WalkArea2 = 10
+};
+
+enum {
+ kHS26Platypus = 0,
+ kHS26ExitOutsideCircusWorld = 1,
+ kHS26ExitOutsideClown = 2,
+ kHS26ExitArcade = 3,
+ kHS26ExitElephant = 4,
+ kHS26ExitBeerStand = 5,
+ kHS26Device = 6,
+ kHS26WalkArea1 = 7,
+ kHS26WalkArea2 = 8
+};
+
+enum {
+ kHS27Platypus = 0,
+ kHS27Janitor = 1,
+ kHS27Device = 2,
+ kHS27Bucket = 3,
+ kHS27ExitCircus = 4,
+ kHS27ExitArcade = 5,
+ kHS27ExitBeerStand = 6,
+ kHS27ExitClown = 7,
+ kHS27WalkArea1 = 8
+};
+
+enum {
+ kHS28Platypus = 0,
+ kHS28Horn = 1,
+ kHS28Clown = 2,
+ kHS28ExitOutsideClown = 3,
+ kHS28EmptyBucket = 4,
+ kHS28Device = 5,
+ kHS28WalkArea1 = 6,
+ kHS28WalkArea2 = 7
+};
+
+enum {
+ kHS29Platypus = 0,
+ kHS29Monkey = 1,
+ kHS29Device = 2,
+ kHS29ExitCircus = 3,
+ kHS29ExitOutsideClown = 4,
+ kHS29Arcade = 5,
+ kHS29WalkArea1 = 6
+};
+
+enum {
+ kAS20LeaveScene = 0,
+ kAS20TalkStonerGuyNoJoint = 2,
+ kAS20TalkStonerGuyHasJoint = 3,
+ kAS20GrabJoint = 4,
+ kAS20ActionDone = 5,
+ kAS20TalkGroceryStoreGuy = 6,
+ kAS20GrabGroceryStoreGuy = 9,
+ kAS20GrabGroceryStoreHat = 10,
+ kAS20SwitchGroceryStoreHat = 11,
+ kAS20SwitchGroceryStoreHatDone = 12,
+ kAS20GrabJointDone = 13
+};
+
+enum {
+ kAS21TalkOldLady = 0,
+ kAS21GrabBanana = 1,
+ kAS21GrabBananaDone = 2,
+ kAS21GrabOldLady = 3,
+ kAS21UseHatWithOldLady = 4,
+ kAS21UseHatWithOldLadyDone = 5,
+ kAS21LeaveScene = 6
+};
+
+enum {
+ kAS22LeaveScene = 0,
+ kAS22TalkCashier = 1
+};
+
+enum {
+ kAS23LookCereals = 0,
+ kAS23GrabCereals = 1,
+ kAS23GrabCerealsDone = 2,
+ kAS23LeaveScene = 3
+};
+
+enum {
+ kAS24LeaveScene = 0
+};
+
+enum {
+ kAS25TalkTicketVendor = 0,
+ kAS25EnterCircusWihoutTicket = 1,
+ kAS25ShowTicketToVendor = 2,
+ kAS25ShowTicketToVendorDone = 3,
+ kAS25EnterCircusWihoutTicketDone = 4,
+ kAS25LeaveScene = 5
+};
+
+enum {
+ kAS26LeaveScene = 0
+};
+
+enum {
+ kAS27TalkJanitor = 0,
+ kAS27GrabBucket = 1,
+ kAS27GrabBucketDone = 2,
+ kAS27ShowPictureToJanitor = 3,
+ kAS27TryEnterClownTent = 4,
+ kAS27TryEnterClownTentDone = 5,
+ kAS27EnterClownTent = 6,
+ kAS27LeaveScene = 7
+};
+
+enum {
+ kAS28UseBeerBucketWithClown = 0,
+ kAS28UsePillBucketWithClown = 1,
+ kAS28GrabHornFails = 2,
+ kAS28GrabEmptyBucket = 3,
+ kAS28GrabHornSuccess = 4,
+ kAS28GrabHornSuccessDone = 5,
+ kAS28GrabEmptyBucketDone = 6,
+ kAS28GrabHornFailsDone = 7,
+ kAS28TalkClown = 8,
+ kAS28GnapWaiting = 9,
+ kAS28LeaveScene = 10
+};
+
+enum {
+ kAS29UseBananaWithMonkey = 0,
+ kAS29LeaveScene = 2
+};
+
+class GnapEngine;
+class CutScene;
+
+class Scene20: public Scene {
+public:
+ Scene20(GnapEngine *vm);
+ virtual ~Scene20() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb();
+
+private:
+ int _currStonerGuySequenceId;
+ int _nextStonerGuySequenceId;
+ int _currGroceryStoreGuySequenceId;
+ int _nextGroceryStoreGuySequenceId;
+ int _stonerGuyCtr;
+ int _groceryStoreGuyCtr;
+ bool _stonerGuyShowingJoint;
+
+ void stopSounds();
+};
+
+class Scene21: public Scene {
+public:
+ Scene21(GnapEngine *vm);
+ virtual ~Scene21() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currOldLadySequenceId;
+ int _nextOldLadySequenceId;
+};
+
+class Scene22: public Scene {
+public:
+ Scene22(GnapEngine *vm);
+ virtual ~Scene22() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currCashierSequenceId;
+ int _nextCashierSequenceId;
+ bool _caughtBefore;
+ int _cashierCtr;
+};
+
+class Scene23: public Scene {
+public:
+ Scene23(GnapEngine *vm);
+ virtual ~Scene23() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currStoreClerkSequenceId;
+ int _nextStoreClerkSequenceId;
+};
+
+class Scene24: public Scene {
+public:
+ Scene24(GnapEngine *vm);
+ virtual ~Scene24() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currWomanSequenceId;
+ int _nextWomanSequenceId;
+ int _boySequenceId;
+ int _girlSequenceId;
+};
+
+class Scene25: public Scene {
+public:
+ Scene25(GnapEngine *vm);
+ virtual ~Scene25() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currTicketVendorSequenceId;
+ int _nextTicketVendorSequenceId;
+
+ void playAnims(int index);
+};
+
+class Scene26: public Scene {
+public:
+ Scene26(GnapEngine *vm);
+ virtual ~Scene26() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currKidSequenceId;
+ int _nextKidSequenceId;
+};
+
+class Scene27: public Scene {
+public:
+ Scene27(GnapEngine *vm);
+ virtual ~Scene27() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextJanitorSequenceId;
+ int _currJanitorSequenceId;
+};
+
+class Scene28: public Scene {
+public:
+ Scene28(GnapEngine *vm);
+ virtual ~Scene28() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currClownSequenceId;
+ int _nextClownSequenceId;
+ int _clownTalkCtr;
+};
+
+class Scene29: public Scene {
+public:
+ Scene29(GnapEngine *vm);
+ virtual ~Scene29() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currMonkeySequenceId;
+ int _nextMonkeySequenceId;
+ int _currManSequenceId;
+ int _nextManSequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP1_H
diff --git a/engines/gnap/scenes/group3.cpp b/engines/gnap/scenes/group3.cpp
new file mode 100644
index 0000000000..98a4f6c454
--- /dev/null
+++ b/engines/gnap/scenes/group3.cpp
@@ -0,0 +1,1612 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group3.h"
+
+namespace Gnap {
+
+Scene30::Scene30(GnapEngine *vm) : Scene(vm) {
+ _kidSequenceId = -1;
+}
+
+int Scene30::init() {
+ return _vm->isFlag(kGFUnk23) ? 0x10B : 0x10A;
+}
+
+void Scene30::updateHotspots() {
+ _vm->setHotspot(kHS30Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS30PillMachine, 598, 342, 658, 426, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 7);
+ _vm->setHotspot(kHS30ExitCircus, 100, 590 - _vm->_deviceY1, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS30WalkArea1, 0, 0, 800, 514);
+ _vm->setDeviceHotspot(kHS30Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 5;
+}
+
+void Scene30::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ bool hasTakenPill = false;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFUnk23))
+ gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (!_vm->isFlag(kGFUnk13))
+ gameSys.insertSequence(0x107, 1, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+
+ gameSys.insertSequence(0x101, 40, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ _kidSequenceId = 0x101;
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS30Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS30Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS30PillMachine:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole && !_vm->isFlag(kGFUnk23)) {
+ _vm->_hotspots[kHS30WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine], 0, 0x107BC, 1);
+ _vm->_hotspots[kHS30WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS30UsePillMachine;
+ hasTakenPill = true;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS30PillMachine], 8, 5);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(Common::Point(9, 8), 0, 0x107BC, 1);
+ gnap._actionStatus = kAS30LookPillMachine;
+ break;
+ case GRAB_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 5));
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible(Common::Point(8, 5));
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS30ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ if (hasTakenPill)
+ _vm->_newSceneNum = 47;
+ else
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS30ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS30LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS30ExitCircus] + Common::Point(1, 0), -1, 0x107C2, 1);
+ }
+ break;
+
+ case kHS30WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(5) == 1) {
+ gameSys.insertSequence(0xFF, 40, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x100, 40, _kidSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _kidSequenceId = 0x100;
+ } else {
+ gameSys.insertSequence(0xFE, 40, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+ if (gnap._actionStatus < 0) {
+ if (!_vm->isFlag(kGFUnk23) || hasTakenPill)
+ gameSys.insertSequence(0x109, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x108, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene30::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS30LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS30UsePillMachine:
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x105, gnap._id, 0);
+ gameSys.insertSequence(0x105, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x105;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS30UsePillMachine2;
+ break;
+ case kAS30UsePillMachine2:
+ _vm->hideCursor();
+ _vm->setGrabCursorSprite(-1);
+ _vm->addFullScreenSprite(0x3F, 255);
+ gameSys.removeSequence(0x105, gnap._id, true);
+ gameSys.setAnimation(0x102, 256, 0);
+ gameSys.insertSequence(0x102, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x103, gnap._id, 0);
+ gameSys.insertSequence(0x103, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ gnap._actionStatus = kAS30UsePillMachine3;
+ _vm->invAdd(kItemPill);
+ _vm->setFlag(kGFUnk23);
+ break;
+ case kAS30UsePillMachine3:
+ gameSys.setAnimation(0x104, gnap._id, 0);
+ gameSys.insertSequence(0x104, gnap._id, makeRid(gnap._sequenceDatNum, 0x103), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x104;
+ gnap._sequenceDatNum = 0;
+ gnap._actionStatus = kAS30UsePillMachine4;
+ _vm->setGrabCursorSprite(kItemDiceQuarterHole);
+ break;
+ case kAS30UsePillMachine4:
+ gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine] + Common::Point(0, 1), -1, 0x107BC, 1);
+ gnap._actionStatus = -1;
+ break;
+ case kAS30LookPillMachine:
+ if (_vm->isFlag(kGFUnk23))
+ _vm->showFullScreenSprite(0xE3);
+ else
+ _vm->showFullScreenSprite(0xE2);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene31::Scene31(GnapEngine *vm) : Scene(vm) {
+ _beerGuyDistracted = false;
+ _currClerkSequenceId = -1;
+ _nextClerkSequenceId = -1;
+ _clerkMeasureCtr = -1;
+ _clerkMeasureMaxCtr = 3;
+}
+
+int Scene31::init() {
+ return 0x105;
+}
+
+void Scene31::updateHotspots() {
+ _vm->setHotspot(kHS31Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS31MeasuringClown, 34, 150, 256, 436, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 6);
+ _vm->setHotspot(kHS31BeerBarrel, 452, 182, 560, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS31ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS31ExitOutsideClown, 0, 0, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS31WalkArea1, 0, 0, 800, 480);
+ _vm->setDeviceHotspot(kHS31Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene31::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1093B, true);
+ _vm->startSoundTimerB(6);
+ _vm->queueInsertDeviceIcon();
+
+ _beerGuyDistracted = false;
+ gameSys.insertSequence(0xFB, 39, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currClerkSequenceId = 0xFB;
+ _nextClerkSequenceId = -1;
+
+ gameSys.setAnimation(0xFB, 39, 3);
+
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+
+ if (_vm->_prevSceneNum == 27) {
+ gnap.initPos(-1, 8, kDirBottomLeft);
+ plat.initPos(-1, 9, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(3, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(3, 9), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(7, 12, kDirBottomRight);
+ plat.initPos(6, 12, kDirIdleLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(7, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107D2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS31Device:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS31Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemJoint) {
+ gnap.useJointOnPlatypus();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31MeasuringClown:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (_vm->_verbCursor == LOOK_CURSOR)
+ gnap.playScratchingHead(Common::Point(2, 2));
+ else
+ gnap.playImpossible();
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 2, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(2, 2));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), -1, -1, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 0, 0x107B9, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE;
+ gnap._actionStatus = kAS31UseMeasuringClown;
+ _vm->_timers[4] = 300;
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ if (!_vm->invHas(kItemBucketWithBeer)) {
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 1, 0x107C2, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 1, 0x107C2, 1);
+ _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE;
+ plat._actionStatus = kAS31PlatMeasuringClown;
+ gnap._actionStatus = kAS31PlatMeasuringClown;
+ _vm->_timers[4] = 300;
+ } else
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31BeerBarrel:
+ if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) {
+ if (_vm->_grabCursorSpriteIndex == kItemEmptyBucket && _beerGuyDistracted) {
+ _vm->setGrabCursorSprite(-1);
+ gnap.walkTo(gnap._pos, -1, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS31BeerBarrel]) | 0x10000, 1);
+ _clerkMeasureMaxCtr += 5;
+ gameSys.insertSequence(0xF8, 59, 0, 0, kSeqNone, 0, 0, 0);
+ gnap.playPullOutDevice(Common::Point(6, 8));
+ gnap.playUseDevice();
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS31FillEmptyBucketWithBeer;
+ _vm->_timers[4] = 300;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 6, 2);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(6, 2));
+ break;
+ case GRAB_CURSOR:
+ if (_beerGuyDistracted) {
+ gnap.playScratchingHead(Common::Point(6, 2));
+ } else {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS31UseBeerBarrel;
+ gnap._idleFacing = kDirUpLeft;
+ }
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS31ExitCircus:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 26;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitCircus].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS31LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitCircus] + Common::Point(1, 0), -1, -1, 1);
+ }
+ break;
+
+ case kHS31ExitOutsideClown:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 27;
+ gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitOutsideClown].y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS31LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitOutsideClown] + Common::Point(0, 1), -1, 0x107CF, 1);
+ }
+ break;
+
+ case kHS31WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1093B))
+ _vm->playSound(0x1093B, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 60;
+ if (gnap._actionStatus < 0 && _nextClerkSequenceId == -1) {
+ switch (_vm->getRandom(6)){
+ case 0:
+ _nextClerkSequenceId = 0xFF;
+ break;
+ case 1:
+ _nextClerkSequenceId = 0x100;
+ break;
+ case 2:
+ _nextClerkSequenceId = 0x101;
+ break;
+ default:
+ _nextClerkSequenceId = 0xFB;
+ break;
+ }
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 180;
+ if (gnap._actionStatus < 0) {
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x104, 20, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x103, 20, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ }
+ _vm->playSoundB();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene31::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS31UseBeerBarrel:
+ _nextClerkSequenceId = 0xFE;
+ break;
+ case kAS31FillEmptyBucketWithBeer:
+ gameSys.setAnimation(0x102, 59, 0);
+ gameSys.insertSequence(0x102, 59, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._pos = Common::Point(5, 7);
+ gnap._sequenceDatNum = 0;
+ gnap._sequenceId = 0x102;
+ gnap._id = 59;
+ gnap._actionStatus = kAS31FillEmptyBucketWithBeerDone;
+ break;
+ case kAS31FillEmptyBucketWithBeerDone:
+ gnap._idleFacing = kDirBottomLeft;
+ gnap.playPullOutDevice();
+ gnap.playUseDevice();
+ gameSys.insertSequence(0xF9, 59, 0xF8, 59, kSeqSyncWait, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->invAdd(kItemBucketWithBeer);
+ _vm->invRemove(kItemEmptyBucket);
+ _vm->setGrabCursorSprite(kItemBucketWithBeer);
+ break;
+ case kAS31UseMeasuringClown:
+ _nextClerkSequenceId = 0xFA;
+ _clerkMeasureMaxCtr = 1;
+ break;
+ case kAS31LeaveScene:
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._actionStatus == kAS31PlatMeasuringClown) {
+ _vm->_sceneWaiting = true;
+ _beerGuyDistracted = true;
+ _nextClerkSequenceId = 0xFA;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_nextClerkSequenceId) {
+ case 0xFA:
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.insertSequence(0xFC, 39, _nextClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0xFC, 39, 3);
+ _currClerkSequenceId = 0xFC;
+ _nextClerkSequenceId = 0xFC;
+ _clerkMeasureCtr = 0;
+ break;
+ case 0xFC:
+ ++_clerkMeasureCtr;
+ if (_clerkMeasureCtr >= _clerkMeasureMaxCtr) {
+ if (gnap._actionStatus != 5)
+ plat._actionStatus = -1;
+ _vm->_timers[0] = 40;
+ gameSys.insertSequence(0xFD, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClerkSequenceId = 0xFD;
+ _nextClerkSequenceId = -1;
+ if (gnap._actionStatus != kAS31FillEmptyBucketWithBeerDone && gnap._actionStatus != kAS31FillEmptyBucketWithBeer)
+ gnap._actionStatus = -1;
+ _beerGuyDistracted = false;
+ _clerkMeasureMaxCtr = 3;
+ gameSys.setAnimation(0xFD, 39, 3);
+ _vm->_sceneWaiting = false;
+ } else {
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = 0xFC;
+ gameSys.setAnimation(0xFC, 39, 3);
+ }
+ break;
+ case 0xFE:
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClerkSequenceId, 39, 3);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = -1;
+ gnap._actionStatus = -1;
+ break;
+ default:
+ if (_nextClerkSequenceId != -1) {
+ gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextClerkSequenceId, 39, 3);
+ _currClerkSequenceId = _nextClerkSequenceId;
+ _nextClerkSequenceId = -1;
+ }
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene32::Scene32(GnapEngine *vm) : Scene(vm) {}
+
+int Scene32::init() {
+ _vm->_gameSys->setAnimation(0, 0, 0);
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0xF : 0x10;
+}
+
+void Scene32::updateHotspots() {
+ _vm->setHotspot(kHS32Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS32ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6);
+ _vm->setHotspot(kHS32WalkArea1, 0, 0, 162, 426);
+ _vm->setHotspot(kHS32WalkArea2, 162, 0, 237, 396);
+ _vm->setHotspot(kHS32WalkArea3, 237, 0, 319, 363);
+ _vm->setHotspot(kHS32WalkArea4, 520, 0, 800, 404);
+ _vm->setHotspot(kHS32WalkArea5, 300, 447, 800, 600);
+ _vm->setHotspot(kHS32WalkArea6, 678, 0, 800, 404);
+ _vm->setHotspot(kHS32WalkArea7, 0, 0, 520, 351);
+ _vm->setHotspot(kHS32WalkArea8, 0, 546, 300, 600);
+ _vm->setDeviceHotspot(kHS32Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 11;
+}
+
+void Scene32::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(5);
+ _vm->queueInsertDeviceIcon();
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ if (_vm->_prevSceneNum == 33) {
+ gnap.initPos(11, 6, kDirBottomLeft);
+ plat.initPos(12, 6, kDirIdleRight);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(9, 6), -1, 0x107D2, 1);
+ gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1);
+ } else {
+ gnap.initPos(1, 6, kDirBottomRight);
+ plat.initPos(1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS32Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS32Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS32ExitTruck:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->setGrabCursorSprite(-1);
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS32LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck] + Common::Point(0, 1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 33;
+ }
+ break;
+
+ case kHS32WalkArea1:
+ case kHS32WalkArea2:
+ case kHS32WalkArea3:
+ case kHS32WalkArea4:
+ case kHS32WalkArea5:
+ case kHS32WalkArea6:
+ case kHS32WalkArea7:
+ case kHS32WalkArea8:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = 0;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x0E, 180, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x0D, 180, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene32::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (_vm->_gnap->_actionStatus == kAS32LeaveScene)
+ _vm->_sceneDone = true;
+ }
+}
+
+/*****************************************************************************/
+
+Scene33::Scene33(GnapEngine *vm) : Scene(vm) {
+ _currChickenSequenceId = -1;
+ _nextChickenSequenceId = -1;
+}
+
+int Scene33::init() {
+ return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x84 : 0x85;
+}
+
+void Scene33::updateHotspots() {
+ _vm->setHotspot(kHS33Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS33Chicken, 606, 455, 702, 568, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS33ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 3);
+ _vm->setHotspot(kHS33ExitBarn, 610, 75, 800, 164, SF_EXIT_U_CURSOR, 10, 3);
+ _vm->setHotspot(kHS33ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS33ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS33WalkArea1, 120, 0, 514, 458);
+ _vm->setHotspot(kHS33WalkArea2, 0, 0, 800, 452);
+ _vm->setDeviceHotspot(kHS33Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene33::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->playSound(0x1091C, true);
+ _vm->startSoundTimerC(6);
+ _vm->queueInsertDeviceIcon();
+
+ _currChickenSequenceId = 0x7E;
+ gameSys.setAnimation(0x7E, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ _nextChickenSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+
+ switch (_vm->_prevSceneNum) {
+ case 34:
+ gnap.initPos(11, 7, kDirBottomLeft);
+ plat.initPos(12, 7, kDirIdleRight);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 7), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1);
+ break;
+ case 37:
+ gnap.initPos(7, 7, kDirBottomRight);
+ plat.initPos(8, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ case 32:
+ gnap.initPos(-1, 6, kDirBottomRight);
+ plat.initPos(-1, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ break;
+ default:
+ gnap.initPos(3, 7, kDirBottomRight);
+ plat.initPos(2, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ break;
+ }
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+ _vm->testWalk(0, 0, 7, 6, 8, 6);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS33Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+
+ case kHS33Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS33Chicken:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 9), 9, 8);
+ } else {
+ switch (_vm->_verbCursor) {
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1))
+ gnap._actionStatus = kAS33UseChicken;
+ else
+ gnap._actionStatus = -1;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirBottomRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS33TalkChicken;
+ break;
+ case LOOK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS33ExitHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap._actionStatus = kAS33LeaveScene;
+ _vm->_newSceneNum = 37;
+ if (gnap._pos.x > 6)
+ gnap.walkTo(gnap._pos, 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(6, 7), 0, 0x107B1, 1);
+ }
+ break;
+
+ case kHS33ExitBarn:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap._actionStatus = kAS33LeaveScene;
+ _vm->_newSceneNum = 35;
+ if (gnap._pos.x > 7)
+ gnap.walkTo(gnap._pos, 0, 0x107AD, 1);
+ else
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107B1, 1);
+ }
+ break;
+
+ case kHS33ExitCreek:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], 0, 0x107AB, 1);
+ gnap._actionStatus = kAS33LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 34;
+ }
+ break;
+
+ case kHS33ExitPigpen:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], 0, 0x107AF, 1);
+ gnap._actionStatus = kAS33LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 32;
+ }
+ break;
+
+ case kHS33WalkArea1:
+ case kHS33WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->isSoundPlaying(0x1091C))
+ _vm->playSound(0x1091C, true);
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 300;
+ if (_vm->getRandom(2) != 0)
+ gameSys.insertSequence(0x83, 256, 0, 0, kSeqNone, 0, 0, 0);
+ else
+ gameSys.insertSequence(0x82, 256, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != kAS33TalkChicken && gnap._actionStatus != kAS33UseChicken) {
+ if (_vm->getRandom(6) != 0) {
+ _nextChickenSequenceId = 0x7E;
+ _vm->_timers[5] = _vm->getRandom(20) + 30;
+ } else {
+ _nextChickenSequenceId = 0x80;
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+ }
+ _vm->playSoundC();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene33::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS33LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS33TalkChicken:
+ _nextChickenSequenceId = 0x7F;
+ break;
+ case kAS33UseChicken:
+ _nextChickenSequenceId = 0x81;
+ _vm->_timers[2] = 100;
+ break;
+ case kAS33UseChickenDone:
+ gameSys.insertSequence(0x107B5, gnap._id, 0x81, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceId = 0x7B5;
+ gnap._sequenceDatNum = 1;
+ _currChickenSequenceId = 0x7E;
+ gameSys.setAnimation(0x7E, 179, 2);
+ gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_timers[5] = 30;
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextChickenSequenceId == 0x81) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 0);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(_currChickenSequenceId, 179, true);
+ _nextChickenSequenceId = -1;
+ _currChickenSequenceId = -1;
+ gnap._actionStatus = kAS33UseChickenDone;
+ _vm->_timers[5] = 500;
+ } else if (_nextChickenSequenceId == 0x7F) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ gnap._actionStatus = -1;
+ } else if (_nextChickenSequenceId != -1) {
+ gameSys.setAnimation(_nextChickenSequenceId, 179, 2);
+ gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0);
+ _currChickenSequenceId = _nextChickenSequenceId;
+ _nextChickenSequenceId = -1;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene38::Scene38(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene38::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0xA5;
+}
+
+void Scene38::updateHotspots() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->setHotspot(kHS38Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS38ExitHouse, 150, 585, 650, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38ExitCave, 430, 440, 655, 470, SF_WALKABLE, 0, 8);
+ _vm->setHotspot(kHS38TrapDoorLid1, 525, 265, 640, 350, SF_DISABLED);
+ _vm->setHotspot(kHS38TrapDoorLid2, 555, 350, 670, 430, SF_DISABLED);
+ _vm->setHotspot(kHS38HuntingTrophy, 170, 85, 250, 190, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38WalkArea1, 330, 270, 640, 380, SF_DISABLED | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8);
+ _vm->setHotspot(kHS38WalkArea2, 0, 0, 799, 396);
+ _vm->setHotspot(kHS38WalkArea3, 0, 585, 799, 599, SF_WALKABLE | SF_DISABLED);
+ _vm->setHotspot(kHS38WalkArea4, 0, 0, 97, 445);
+ _vm->setHotspot(kHS38WalkArea5, 770, 0, 799, 445);
+ _vm->setHotspot(kHS38WalkArea6, 393, 0, 698, 445, SF_WALKABLE | SF_DISABLED);
+ _vm->setDeviceHotspot(kHS38Device, -1, -1, -1, -1);
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38Platypus]._flags = SF_WALKABLE | SF_DISABLED;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_DISABLED;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_DISABLED;
+ else if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_hotspots[kHS38WalkArea6]._flags = SF_NONE;
+ _vm->_hotspotsCount = 13;
+}
+
+void Scene38::run() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _vm->_gameSys->insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->_prevSceneNum == 39) {
+ gnap.initPos(3, 7, kDirBottomLeft);
+ plat.initPos(4, 7, kDirIdleRight);
+ } else {
+ gnap.initPos(3, 8, kDirBottomRight);
+ plat.initPos(4, 8, kDirIdleLeft);
+ }
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS38Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS38Platypus:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ break;
+
+ case kHS38ExitHouse:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ } else {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(-1, -1), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS38LeaveScene;
+ _vm->_newSceneNum = 37;
+ }
+ break;
+
+ case kHS38ExitCave:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ _vm->_isLeavingScene = true;
+ } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ _vm->_sceneWaiting = false;
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1);
+ _vm->_newSceneNum = 39;
+ gnap._actionStatus = kAS38ExitCave;
+ }
+ break;
+
+ case kHS38TrapDoorLid1:
+ case kHS38TrapDoorLid2:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy) {
+ if (_vm->_verbCursor == PLAT_CURSOR && plat._actionStatus != kAS38PlatypusHoldingTrapDoor)
+ gnap._actionStatus = kAS38UsePlatypusWithTrapDoor;
+ else
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ }
+ break;
+
+ case kHS38HuntingTrophy:
+ if (gnap._actionStatus != kAS38HoldingHuntingTrophy) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 6), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor)
+ gnap.playImpossible();
+ else {
+ gnap.walkTo(Common::Point(3, 6), 0, 0x107BB, 1);
+ plat.walkTo(Common::Point(4, 8), -1, -1, 1);
+ gnap._actionStatus = kAS38UseHuntingTrophy;
+ }
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(Common::Point(2, 0));
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS38WalkArea1:
+ // Nothing
+ break;
+
+ case kHS38WalkArea2:
+ case kHS38WalkArea3:
+ case kHS38WalkArea4:
+ case kHS38WalkArea5:
+ case kHS38WalkArea6:
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ else if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left) {
+ if (gnap._actionStatus == kAS38HoldingHuntingTrophy)
+ gnap._actionStatus = kAS38ReleaseHuntingTrophy;
+ else if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ plat.updateIdleSequence();
+ gnap.updateIdleSequence();
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene38::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case kAS38LeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS38ExitCave:
+ gameSys.removeSequence(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, true);
+ gameSys.insertSequence(0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA3;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0xA3, gnap._id, 0);
+ gnap._actionStatus = kAS38LeaveScene;
+ break;
+ case kAS38UseHuntingTrophy:
+ gameSys.removeSequence(0x9B, 0, true);
+ gameSys.insertSequence(0x9C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9C;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9C, gnap._id, 0);
+ gnap._actionStatus = kAS38HoldingHuntingTrophy;
+ updateHotspots();
+ break;
+ case kAS38HoldingHuntingTrophy:
+ if (plat._actionStatus != kAS38PlatypusHoldingTrapDoor)
+ _vm->_sceneWaiting = true;
+ if (gnap._sequenceId == 0xA4) {
+ gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9D;
+ } else {
+ gameSys.insertSequence(0xA4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA4;
+ }
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(gnap._sequenceId, gnap._id, 0);
+ break;
+ case kAS38ReleaseHuntingTrophy:
+ if (gnap._sequenceId == 0x9E) {
+ gameSys.insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0);
+ gnap._actionStatus = -1;
+ } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ gameSys.insertSequence(0xA0, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0xA0;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(3, 6);
+ gnap._idleFacing = kDirBottomRight;
+ if (_vm->_isLeavingScene) {
+ _vm->_sceneWaiting = false;
+ gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1);
+ _vm->_newSceneNum = 39;
+ gnap._actionStatus = kAS38ExitCave;
+ } else {
+ gnap._actionStatus = -1;
+ }
+ } else {
+ gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gnap._pos = Common::Point(3, 6);
+ gnap._idleFacing = kDirBottomRight;
+ gameSys.setAnimation(0x9E, gnap._id, 0);
+ _vm->_sceneWaiting = false;
+ updateHotspots();
+ }
+ break;
+ case kAS38UsePlatypusWithTrapDoor:
+ _vm->_sceneWaiting = false;
+ gameSys.insertSequence(0x9F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9F;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9F, gnap._id, 0);
+ gnap._actionStatus = kAS38HoldingHuntingTrophy;
+ if (plat._idleFacing != kDirIdleLeft)
+ plat.playSequence(0x107D5);
+ else
+ plat.playSequence(0x107D4);
+ plat.walkTo(Common::Point(8, 7), -1, 0x107D2, 1);
+ gameSys.insertSequence(0xA1, gnap._id + 1, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xA1;
+ plat._sequenceDatNum = 0;
+ plat._id = gnap._id + 1;
+ gameSys.setAnimation(0xA1, gnap._id + 1, 1);
+ plat._actionStatus = kAS38PlatypusHoldingTrapDoor;
+ updateHotspots();
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) {
+ gameSys.insertSequence(0xA2, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xA2;
+ plat._sequenceDatNum = 0;
+ updateHotspots();
+ _vm->_sceneWaiting = true;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene39::Scene39(GnapEngine *vm) : Scene(vm) {
+ _currGuySequenceId = -1;
+ _nextGuySequenceId = -1;
+}
+
+int Scene39::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x35;
+}
+
+void Scene39::updateHotspots() {
+ _vm->setHotspot(kHS39Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS39ExitInsideHouse, 0, 0, 140, 206, SF_EXIT_U_CURSOR, 4, 8);
+ _vm->setHotspot(kHS39ExitUfoParty, 360, 204, 480, 430, SF_EXIT_R_CURSOR, 6, 8);
+ _vm->setHotspot(kHS39Sign, 528, 232, 607, 397, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 3);
+ _vm->setHotspot(kHS39WalkArea1, 0, 0, 800, 466);
+ _vm->setHotspot(kHS39WalkArea2, 502, 466, 800, 600);
+ _vm->setDeviceHotspot(kHS39Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 7;
+}
+
+void Scene39::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ // Bug in the original? Timer was never initialized.
+ _vm->_timers[5] = 0;
+
+ _vm->queueInsertDeviceIcon();
+ _currGuySequenceId = 0x33;
+
+ gameSys.setAnimation(0x33, 21, 3);
+ gameSys.insertSequence(_currGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x34, 21, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _nextGuySequenceId = -1;
+ if (_vm->_prevSceneNum == 38) {
+ gnap.initPos(3, 7, kDirUpRight);
+ plat.initPos(2, 7, kDirUpLeft);
+ _vm->endSceneInit();
+ } else {
+ gnap.initPos(4, 7, kDirBottomRight);
+ plat.initPos(5, 7, kDirIdleLeft);
+ _vm->endSceneInit();
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B)) {
+ _vm->playSound(0x1094B, true);
+ _vm->setSoundVolume(0x1094B, 60);
+ }
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS39Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ break;
+
+ case kHS39Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS39ExitUfoParty:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap.walkTo(gnap._pos, 0, 0x107AB, 1);
+ gnap._actionStatus = kAS39LeaveScene;
+ _vm->_newSceneNum = 40;
+ }
+ break;
+
+ case kHS39Sign:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible();
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS39Sign], 0, -1, 1);
+ gnap.playIdle(_vm->_hotspotsWalkPos[kHS39Sign]);
+ _vm->showFullScreenSprite(0x1C);
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS39ExitInsideHouse:
+ if (gnap._actionStatus < 0) {
+ _vm->_sceneDone = true;
+ _vm->_isLeavingScene = true;
+ _vm->_newSceneNum = 38;
+ }
+ break;
+
+ case kHS39WalkArea1:
+ case kHS39WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ _vm->_mouseClickState._left = false;
+ }
+ break;
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0)
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ _nextGuySequenceId = 0x30;
+ break;
+ case 1:
+ _nextGuySequenceId = 0x31;
+ break;
+ case 2:
+ _nextGuySequenceId = 0x32;
+ break;
+ case 3:
+ _nextGuySequenceId = 0x33;
+ break;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[5] = _vm->getRandom(20) + 50;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene39::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus == kAS39LeaveScene)
+ _vm->_sceneDone = true;
+ else
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextGuySequenceId != -1) {
+ gameSys.setAnimation(_nextGuySequenceId, 21, 3);
+ gameSys.insertSequence(_nextGuySequenceId, 21, _currGuySequenceId, 21, kSeqSyncWait, 0, 0, 0);
+ _currGuySequenceId = _nextGuySequenceId;
+ _nextGuySequenceId = -1;
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group3.h b/engines/gnap/scenes/group3.h
new file mode 100644
index 0000000000..6fbbdd79aa
--- /dev/null
+++ b/engines/gnap/scenes/group3.h
@@ -0,0 +1,240 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GROUP3_H
+#define GNAP_GROUP3_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS30Platypus = 0,
+ kHS30PillMachine = 1,
+ kHS30Device = 2,
+ kHS30ExitCircus = 3,
+ kHS30WalkArea1 = 4
+};
+
+enum {
+ kHS31Platypus = 0,
+ kHS31MeasuringClown = 1,
+ kHS31BeerBarrel = 2,
+ kHS31Device = 3,
+ kHS31ExitCircus = 4,
+ kHS31ExitOutsideClown = 5,
+ kHS31WalkArea1 = 6
+};
+
+enum {
+ kHS32Platypus = 0,
+ kHS32ExitTruck = 1,
+ kHS32Device = 2,
+ kHS32WalkArea1 = 3,
+ kHS32WalkArea2 = 4,
+ kHS32WalkArea3 = 5,
+ kHS32WalkArea4 = 6,
+ kHS32WalkArea5 = 7,
+ kHS32WalkArea6 = 8,
+ kHS32WalkArea7 = 9,
+ kHS32WalkArea8 = 10
+};
+
+enum {
+ kHS33Platypus = 0,
+ kHS33Chicken = 1,
+ kHS33Device = 2,
+ kHS33ExitHouse = 3,
+ kHS33ExitBarn = 4,
+ kHS33ExitCreek = 5,
+ kHS33ExitPigpen = 6,
+ kHS33WalkArea1 = 7,
+ kHS33WalkArea2 = 8
+};
+
+enum {
+ kHS38Platypus = 0,
+ kHS38ExitHouse = 1,
+ kHS38ExitCave = 2,
+ kHS38TrapDoorLid1 = 3,
+ kHS38TrapDoorLid2 = 4,
+ kHS38HuntingTrophy = 5,
+ kHS38WalkArea1 = 6,
+ kHS38Device = 7,
+ kHS38WalkArea2 = 8,
+ kHS38WalkArea3 = 9,
+ kHS38WalkArea4 = 10,
+ kHS38WalkArea5 = 11,
+ kHS38WalkArea6 = 12
+};
+
+enum {
+ kHS39Platypus = 0,
+ kHS39ExitInsideHouse = 1,
+ kHS39ExitUfoParty = 2,
+ kHS39Sign = 3,
+ kHS39Device = 4,
+ kHS39WalkArea1 = 5,
+ kHS39WalkArea2 = 6
+};
+
+enum {
+ kAS30LeaveScene = 0,
+ kAS30UsePillMachine = 1,
+ kAS30UsePillMachine2 = 2,
+ kAS30LookPillMachine = 3,
+ kAS30UsePillMachine3 = 4,
+ kAS30UsePillMachine4 = 5
+};
+
+enum {
+ kAS31UseBeerBarrel = 1,
+ kAS31FillEmptyBucketWithBeer = 2,
+ kAS31FillEmptyBucketWithBeerDone = 3,
+ kAS31PlatMeasuringClown = 4,
+ kAS31UseMeasuringClown = 5,
+ kAS31LeaveScene = 6
+};
+
+enum {
+ kAS32LeaveScene = 0
+};
+
+enum {
+ kAS33LeaveScene = 0,
+ kAS33TalkChicken = 1,
+ kAS33UseChicken = 2,
+ kAS33UseChickenDone = 3
+};
+
+enum {
+ kAS38LeaveScene = 0,
+ kAS38ExitCave = 1,
+ kAS38UseHuntingTrophy = 2,
+ kAS38HoldingHuntingTrophy = 3,
+ kAS38ReleaseHuntingTrophy = 4,
+ kAS38UsePlatypusWithTrapDoor = 5,
+ kAS38PlatypusHoldingTrapDoor = 6
+};
+
+enum {
+ kAS39LeaveScene = 0
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene30: public Scene {
+public:
+ Scene30(GnapEngine *vm);
+ virtual ~Scene30() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _kidSequenceId;
+};
+
+class Scene31: public Scene {
+public:
+ Scene31(GnapEngine *vm);
+ virtual ~Scene31() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _beerGuyDistracted;
+ int _currClerkSequenceId;
+ int _nextClerkSequenceId;
+ int _clerkMeasureCtr;
+ int _clerkMeasureMaxCtr;
+};
+
+class Scene32: public Scene {
+public:
+ Scene32(GnapEngine *vm);
+ virtual ~Scene32() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene33: public Scene {
+public:
+ Scene33(GnapEngine *vm);
+ virtual ~Scene33() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currChickenSequenceId;
+ int _nextChickenSequenceId;
+};
+
+class Scene38: public Scene {
+public:
+ Scene38(GnapEngine *vm);
+ virtual ~Scene38() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene39: public Scene {
+public:
+ Scene39(GnapEngine *vm);
+ virtual ~Scene39() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currGuySequenceId;
+ int _nextGuySequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP3_H
diff --git a/engines/gnap/scenes/group4.cpp b/engines/gnap/scenes/group4.cpp
new file mode 100644
index 0000000000..f37be2c25d
--- /dev/null
+++ b/engines/gnap/scenes/group4.cpp
@@ -0,0 +1,2799 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group4.h"
+
+namespace Gnap {
+
+Scene40::Scene40(GnapEngine *vm) : Scene(vm) {
+}
+
+int Scene40::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return _vm->isFlag(kGFUnk23) ? 0x01 : 0x00;
+}
+
+void Scene40::updateHotspots() {
+ _vm->setHotspot(kHS40Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_DISABLED | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS40ExitCave, 169, 510, 264, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitToyStand, 238, 297, 328, 376, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitBBQ, 328, 220, 401, 306, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitUfo, 421, 215, 501, 282, SF_EXIT_U_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitKissinBooth, 476, 284, 556, 345, SF_EXIT_R_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitDancefloor, 317, 455, 445, 600, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setHotspot(kHS40ExitShoe, 455, 346, 549, 417, SF_EXIT_D_CURSOR, 0, 8);
+ _vm->setDeviceHotspot(kHS40Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+}
+
+void Scene40::run() {
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ _vm->endSceneInit();
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS40Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS40Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS40ExitCave:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 39;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitToyStand:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 41;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitBBQ:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 42;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitUfo:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 43;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitKissinBooth:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 44;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitDancefloor:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 45;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ case kHS40ExitShoe:
+ if (gnap._actionStatus < 0) {
+ _vm->_newSceneNum = 46;
+ _vm->_sceneDone = true;
+ }
+ break;
+
+ default:
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0)
+ _vm->_mouseClickState._left = false;
+ break;
+
+ }
+
+ updateAnimations();
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene40::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ if (gnap._actionStatus)
+ gnap._actionStatus = -1;
+ else
+ _vm->_sceneDone = true;
+ }
+}
+
+/*****************************************************************************/
+
+Scene41::Scene41(GnapEngine *vm) : Scene(vm) {
+ _currKidSequenceId = -1;
+ _nextKidSequenceId = -1;
+ _currToyVendorSequenceId = -1;
+ _nextToyVendorSequenceId = -1;
+}
+
+int Scene41::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x129;
+}
+
+void Scene41::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS41UfoExitLeft, 0, 0, 10, 500, SF_EXIT_L_CURSOR | SF_DISABLED);
+ _vm->setHotspot(kHS41UfoExitRight, 790, 0, 799, 500, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS41UfoWalkArea1, 0, 0, 800, 470, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS41UfoDevice, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 5;
+ } else {
+ _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41ExitCave, 150, 590, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS41Exit, 0, 100, 10, 599, SF_EXIT_L_CURSOR | SF_DISABLED, 0, 8);
+ _vm->setHotspot(kHS41ExitBBQ, 790, 100, 799, 599, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8);
+ _vm->setHotspot(kHS41ToyVendor, 320, 150, 430, 310, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41Kid, 615, 340, 710, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS41ToyUfo, 0, 0, 0, 0, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS41WalkArea1, 0, 0, 800, 470);
+ _vm->setDeviceHotspot(kHS41Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+ }
+}
+
+void Scene41::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoX = 770;
+ if (_vm->_toyUfoY < 0 || _vm->_toyUfoY > 300)
+ _vm->_toyUfoY = 150;
+ if (!_vm->_timers[9])
+ gnap._actionStatus = kAS41GiveBackToyUfo;
+ } else {
+ if (!_vm->isFlag(kGFUnk16) && !_vm->isFlag(kGFJointTaken) && !_vm->isFlag(kGFUnk18) && !_vm->isFlag(kGFGroceryStoreHatTaken))
+ _vm->toyUfoSetStatus(kGFUnk16);
+ _vm->_toyUfoX = 600;
+ _vm->_toyUfoY = 200;
+ }
+
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ gameSys.insertSequence(0x128, 0, 0, 0, kSeqLoop, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _currKidSequenceId = 0x11B;
+ else
+ _currKidSequenceId = 0x11D;
+
+ _nextKidSequenceId = -1;
+
+ gameSys.setAnimation(_currKidSequenceId, 1, 4);
+ gameSys.insertSequence(_currKidSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currToyVendorSequenceId = 0x118;
+ _nextToyVendorSequenceId = -1;
+
+ gameSys.setAnimation(0x118, 1, 3);
+ gameSys.insertSequence(_currToyVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.insertSequence(0x127, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ gnap._sequenceId = 0x120;
+ gnap._sequenceDatNum = 0;
+ gnap._idleFacing = kDirUpRight;
+ gnap._pos = Common::Point(7, 7);
+ gnap._id = 140;
+ gameSys.insertSequence(0x120, 140, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ plat.initPos(8, 10, kDirBottomLeft);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 45) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-2, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 42) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 8, kDirBottomRight);
+ plat.initPos(6, 8, kDirBottomLeft);
+ _vm->endSceneInit();
+ }
+
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ if (!_vm->isFlag(kGFGnapControlsToyUFO))
+ _vm->_hotspots[kHS41ToyUfo]._rect = Common::Rect(_vm->_toyUfoX - 25, _vm->_toyUfoY - 20, _vm->_toyUfoX + 25, _vm->_toyUfoY + 20);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS41UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene;
+ _vm->_newSceneNum = 45;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2);
+ }
+ break;
+
+ case kHS41UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene;
+ _vm->_newSceneNum = 42;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2);
+ }
+ break;
+
+ case kHS41UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS41Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ break;
+
+ case kHS41Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS41ExitCave:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS41ExitCave], 0, 0x107AE, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS41Exit:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 45;
+ break;
+
+ case kHS41ExitBBQ:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS41LeaveScene;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 42;
+ break;
+
+ case kHS41ToyVendor:
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap._actionStatus = kAS41UseQuarterWithToyVendor;
+ gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 9);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(4, 7), 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS41TalkToyVendor;
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS41Kid:
+ if (_vm->_grabCursorSpriteIndex == kItemChickenBucket) {
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS41UseChickenBucketWithKid;
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(7, 7), 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(9, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1);
+ gnap._idleFacing = kDirUpRight;
+ gnap._actionStatus = kAS41GrabKid;
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(7, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS41ToyUfo:
+ if (_vm->_grabCursorSpriteIndex == kItemGum) {
+ gnap.playPullOutDevice(Common::Point(9, 0));
+ gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0);
+ gnap._actionStatus = kAS41UseGumWithToyUfo;
+ }
+ break;
+
+ case kHS41WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ if (!_vm->_timers[9] && gnap._actionStatus < 0) {
+ gnap._actionStatus = kAS41GiveBackToyUfo;
+ if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x122) {
+ gameSys.insertSequence(0x123, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x123;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x123, gnap._id, 0);
+ }
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ int sequenceId;
+ if (_vm->_leftClickMouseX >= 400) {
+ if (gnap._sequenceId == 0x11F || gnap._sequenceId == 0x120 || gnap._sequenceId == 0x123 || gnap._sequenceId == 0x126)
+ sequenceId = 0x120;
+ else if (_vm->_leftClickMouseX - _vm->_toyUfoX >= 400)
+ sequenceId = 0x126;
+ else
+ sequenceId = 0x123;
+ } else {
+ if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x125 || gnap._sequenceId == 0x122)
+ sequenceId = 0x122;
+ else if (_vm->_toyUfoX - _vm->_leftClickMouseX >= 400)
+ sequenceId = 0x125;
+ else
+ sequenceId = 0x121;
+ }
+ gameSys.insertSequence(sequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = sequenceId;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(sequenceId, gnap._id, 0);
+ _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextToyVendorSequenceId == -1) {
+ switch (_vm->getRandom(3)) {
+ case 0:
+ _nextToyVendorSequenceId = 0x113;
+ break;
+ case 1:
+ _nextToyVendorSequenceId = 0x117;
+ break;
+ case 2:
+ _nextToyVendorSequenceId = 0x119;
+ break;
+ }
+ if (_nextToyVendorSequenceId == _currToyVendorSequenceId)
+ _nextToyVendorSequenceId = -1;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextKidSequenceId == -1) {
+ if (_vm->isFlag(kGFGnapControlsToyUFO))
+ _nextKidSequenceId = 0x11B;
+ else if (_vm->getRandom(3) != 0)
+ _nextKidSequenceId = 0x11D;
+ else
+ _nextKidSequenceId = 0x11E;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene41::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS41LeaveScene:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_sceneDone = true;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41UseQuarterWithToyVendor:
+ gameSys.setAnimation(0, 0, 0);
+ _nextToyVendorSequenceId = 0x114;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41TalkToyVendor:
+ gameSys.setAnimation(0, 0, 0);
+ _nextToyVendorSequenceId = 0x116;
+ gnap._actionStatus = -1;
+ break;
+ case kAS41UseGumWithToyUfo:
+ gameSys.setAnimation(0, 0, 0);
+ gnap.playUseDevice(Common::Point(9, 0));
+ gnap._actionStatus = -1;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemGum);
+ _vm->_toyUfoActionStatus = kAS41UfoGumAttached;
+ break;
+ case kAS41UseChickenBucketWithKid:
+ if (gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ _vm->setGrabCursorSprite(-1);
+ gameSys.insertSequence(0x11F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x11F;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x11F, gnap._id, 0);
+ _nextKidSequenceId = 0x11A;
+ gameSys.insertSequence(0x11A, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = 0x11B;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ _vm->setFlag(kGFGnapControlsToyUFO);
+ updateHotspots();
+ _vm->_timers[9] = 600;
+ }
+ break;
+ case kAS41GrabKid:
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x110, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x110;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x110, gnap._id, 0);
+ _nextToyVendorSequenceId = 0x111;
+ gameSys.insertSequence(0x111, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _nextKidSequenceId = 0x10F;
+ gameSys.insertSequence(0x10F, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ }
+ break;
+ case kAS41GiveBackToyUfo:
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x124, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x124;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x124, gnap._id, 0);
+ _nextToyVendorSequenceId = 0x112;
+ gameSys.insertSequence(0x112, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ _nextKidSequenceId = 0x11C;
+ gameSys.insertSequence(0x11C, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ gnap._actionStatus = -1;
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+ updateHotspots();
+ }
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case kAS41ToyUfoLeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS41UfoGumAttached:
+ _vm->_toyUfoNextSequenceId = 0x873;
+ gameSys.insertSequence(0x10873, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 365, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ _vm->toyUfoSetStatus(kGFJointTaken);
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextToyVendorSequenceId != -1) {
+ gameSys.insertSequence(_nextToyVendorSequenceId, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3);
+ _currToyVendorSequenceId = _nextToyVendorSequenceId;
+ _nextToyVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextKidSequenceId != -1) {
+ gameSys.insertSequence(_nextKidSequenceId, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKidSequenceId, 1, 4);
+ _currKidSequenceId = _nextKidSequenceId;
+ _nextKidSequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(30) + 20;
+ if (_currKidSequenceId == 0x11E) {
+ _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh;
+ _vm->toyUfoFlyTo(_vm->getRandom(300) + 500, _vm->getRandom(225) + 75, 0, 799, 0, 300, 2);
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene42::Scene42(GnapEngine *vm) : Scene(vm) {
+ _currBBQVendorSequenceId = -1;
+ _nextBBQVendorSequenceId = -1;
+}
+
+int Scene42::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ if (_vm->isFlag(kGFPictureTaken) || (_vm->isFlag(kGFUnk18) && _vm->isFlag(kGFUnk23)))
+ return 0x153;
+ return 0x152;
+}
+
+void Scene42::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS42UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS42UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS42UfoHotSauce, 335, 110, 440, 175, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS42UfoDevice, -1, 534, -1, 599);
+ if ((_vm->isFlag(kGFPictureTaken) || _vm->isFlag(kGFUnk18)) && _vm->isFlag(kGFUnk23) && !_vm->isFlag(kGFUnk24))
+ _vm->_hotspots[kHS42UfoHotSauce]._flags = SF_GRAB_CURSOR;
+ _vm->_hotspotsCount = 5;
+ } else {
+ _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS42ExitUfoParty, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS42ExitToyStand, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS42ExitUfo, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS42BBQVendor, 410, 200, 520, 365, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 8);
+ _vm->setHotspot(kHS42ChickenLeg, 530, 340, 620, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 7);
+ _vm->setHotspot(kHS42WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS42WalkArea2, 240, 0, 550, 495);
+ _vm->setDeviceHotspot(kHS42Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 9;
+ }
+}
+
+void Scene42::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ _currBBQVendorSequenceId = 0x14A;
+ _nextBBQVendorSequenceId = -1;
+
+ gameSys.setAnimation(0x14A, 1, 2);
+ gameSys.insertSequence(_currBBQVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ if (_vm->_prevSceneNum == 43 && _vm->isFlag(kGFUnk18)) {
+ _vm->_toyUfoSequenceId = 0x872;
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->_toyUfoX = 317;
+ _vm->_toyUfoY = 61;
+ _vm->toyUfoSetStatus(kGFJointTaken);
+ _vm->setFlag(kGFPictureTaken);
+ _vm->_timers[9] = 600;
+ } else {
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 41)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ }
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ _vm->endSceneInit();
+ if (_vm->_toyUfoSequenceId == 0x872)
+ _vm->setGrabCursorSprite(-1);
+ } else if (_vm->_prevSceneNum == 41) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ } else if (_vm->_prevSceneNum == 43) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS42UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene;
+ _vm->_newSceneNum = 41;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene;
+ _vm->_newSceneNum = 43;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoHotSauce:
+ if (_vm->isFlag(kGFJointTaken)) {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoPickUpHotSauce;
+ _vm->toyUfoFlyTo(384, 77, 0, 799, 0, 300, 3);
+ _vm->_timers[9] = 600;
+ } else {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS42UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS42Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ break;
+
+ case kHS42Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS42ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(Common::Point(plat._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), -1, 0x107C7, 1);
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS42ExitToyStand:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitToyStand].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitToyStand], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 41;
+ break;
+
+ case kHS42ExitUfo:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitUfo].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = kAS42LeaveScene;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitUfo], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 43;
+ break;
+
+ case kHS42BBQVendor:
+ if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, 0x107BB, 1);
+ gnap._actionStatus = kAS42UseQuarterWithBBQVendor;
+ if (plat._pos.y < 9)
+ plat.walkTo(Common::Point(plat._pos.x, 9), -1, -1, 1);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42BBQVendor], _vm->_hotspotsWalkPos[kHS42BBQVendor].x + 1, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42BBQVendor].x - 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = kAS42TalkBBQVendor;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS42ChickenLeg:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42ChickenLeg], _vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0));
+ break;
+ case GRAB_CURSOR:
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS42ChickenLeg], 0, 0x107BC, 1);
+ gnap._actionStatus = kAS42GrabChickenLeg;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS42WalkArea1:
+ case kHS42WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextBBQVendorSequenceId == -1) {
+ switch (_vm->getRandom(8)) {
+ case 0:
+ _nextBBQVendorSequenceId = 0x14C;
+ break;
+ case 1:
+ case 2:
+ _nextBBQVendorSequenceId = 0x149;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ _nextBBQVendorSequenceId = 0x14D;
+ break;
+ case 7:
+ _nextBBQVendorSequenceId = 0x14A;
+ break;
+ }
+ if (_nextBBQVendorSequenceId == _currBBQVendorSequenceId && _nextBBQVendorSequenceId != 0x14D)
+ _nextBBQVendorSequenceId = -1;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene42::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case kAS42LeaveScene:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ _vm->_sceneDone = true;
+ break;
+ case kAS42TalkBBQVendor:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ _nextBBQVendorSequenceId = 0x14B;
+ break;
+ case kAS42UseQuarterWithBBQVendor:
+ case kAS42GrabChickenLeg:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ int sequenceId;
+ if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor) {
+ _vm->invRemove(kItemDiceQuarterHole);
+ _vm->invAdd(kItemChickenBucket);
+ _vm->setGrabCursorSprite(-1);
+ sequenceId = 0x150;
+ _nextBBQVendorSequenceId = 0x148;
+ } else if (_vm->isFlag(kGFUnk27)) {
+ if (_vm->isFlag(kGFUnk28)) {
+ sequenceId = 0x7B7;
+ _nextBBQVendorSequenceId = 0x145;
+ } else {
+ _vm->setFlag(kGFUnk28);
+ sequenceId = 0x14F;
+ _nextBBQVendorSequenceId = 0x147;
+ }
+ } else {
+ _vm->setFlag(kGFUnk27);
+ sequenceId = 0x14E;
+ _nextBBQVendorSequenceId = 0x146;
+ }
+ if (sequenceId == 0x7B7) {
+ gameSys.insertSequence(0x107B7, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, _vm->getSequenceTotalDuration(_nextBBQVendorSequenceId),
+ 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ gnap._sequenceDatNum = 1;
+ } else {
+ gameSys.insertSequence(sequenceId, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceDatNum = 0;
+ }
+ gnap._sequenceId = sequenceId;
+ gameSys.setAnimation(sequenceId | (gnap._sequenceDatNum << 16), gnap._id, 0);
+ if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor)
+ gnap._actionStatus = kAS42UseQuarterWithBBQVendorDone;
+ else
+ gnap._actionStatus = -1;
+ gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2);
+ _currBBQVendorSequenceId = _nextBBQVendorSequenceId;
+ if (_nextBBQVendorSequenceId == 0x145)
+ _nextBBQVendorSequenceId = 0x14A;
+ else
+ _nextBBQVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ }
+ break;
+ case kAS42UseQuarterWithBBQVendorDone:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->setGrabCursorSprite(kItemChickenBucket);
+ gnap._actionStatus = -1;
+ break;
+ default:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2 && _nextBBQVendorSequenceId != -1) {
+ gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2);
+ _currBBQVendorSequenceId = _nextBBQVendorSequenceId;
+ _nextBBQVendorSequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 30;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case kAS42ToyUfoLeaveScene:
+ _vm->_sceneDone = true;
+ break;
+ case kAS42ToyUfoPickUpHotSauce:
+ gameSys.insertSequence(0x10870, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ _vm->setFlag(kGFUnk24);
+ updateHotspots();
+ _vm->toyUfoSetStatus(kGFGroceryStoreHatTaken);
+ _vm->_toyUfoSequenceId = 0x870;
+ gameSys.setAnimation(0x10870, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoX = 0x181;
+ _vm->_toyUfoY = 53;
+ break;
+ default:
+ if (_vm->_toyUfoSequenceId == 0x872) {
+ _vm->hideCursor();
+ _vm->addFullScreenSprite(0x13E, 255);
+ gameSys.setAnimation(0x151, 256, 0);
+ gameSys.insertSequence(0x151, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ }
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10, 3);
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ _vm->_toyUfoId = (_vm->_toyUfoId + 1) % 10;
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene43::Scene43(GnapEngine *vm) : Scene(vm) {
+ _currTwoHeadedGuySequenceId = -1;
+ _nextTwoHeadedGuySequenceId = -1;
+}
+
+int Scene43::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ return 0x13F;
+}
+
+void Scene43::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS43UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS43UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setHotspot(kHS43UfoKey, 140, 170, 185, 260, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS43UfoBucket, 475, 290, 545, 365, SF_DISABLED);
+ _vm->setDeviceHotspot(kHS43UfoDevice, -1, 534, -1, 599);
+ if (_vm->isFlag(kGFGroceryStoreHatTaken))
+ _vm->_hotspots[kHS43UfoBucket]._flags = SF_GRAB_CURSOR;
+ // NOTE Bug in the original. Key hotspot wasn't disabled.
+ if (_vm->isFlag(kGFUnk14))
+ _vm->_hotspots[kHS43UfoKey]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 6;
+ } else {
+ _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS43ExitBBQ, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS43ExitKissinBooth, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS43TwoHeadedGuy, 470, 240, 700, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43Key, 140, 170, 185, 260, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43Ufo, 110, 0, 690, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS43WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS43WalkArea2, 465, 0, 800, 493);
+ _vm->setDeviceHotspot(kHS43Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk14))
+ _vm->_hotspots[kHS43Key]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 10;
+ }
+}
+
+void Scene43::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (!_vm->isFlag(kGFUnk14))
+ gameSys.insertSequence(0x1086F, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currTwoHeadedGuySequenceId = 0x13C;
+ _nextTwoHeadedGuySequenceId = -1;
+
+ gameSys.setAnimation(0x13C, 1, 2);
+ gameSys.insertSequence(_currTwoHeadedGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 42)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 42:
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ break;
+ case 44:
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ break;
+ case 54:
+ gnap.initPos(4, 7, kDirBottomLeft);
+ plat.initPos(11, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ break;
+ default:
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS43UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ break;
+
+ case kHS43UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 4;
+ _vm->_newSceneNum = 42;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 4;
+ _vm->_newSceneNum = 44;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoKey:
+ if (_vm->isFlag(kGFJointTaken)) {
+ _vm->_toyUfoActionStatus = 6;
+ _vm->toyUfoFlyTo(163, 145, 0, 799, 0, 300, 3);
+ } else {
+ _vm->_toyUfoActionStatus = 5;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS43UfoBucket:
+ _vm->_toyUfoActionStatus = 7;
+ _vm->toyUfoFlyTo(497, 143, 0, 799, 0, 300, 3);
+ _vm->_timers[9] = 600;
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS43Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ break;
+
+ case kHS43Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS43ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], -1, 0x107C7, 1);
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS43ExitBBQ:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitBBQ].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitBBQ], -1, 0x107CF, 1);
+ _vm->_newSceneNum = 42;
+ break;
+
+ case kHS43ExitKissinBooth:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth], -1, 0x107CD, 1);
+ _vm->_newSceneNum = 44;
+ break;
+
+ case kHS43TwoHeadedGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(6, 8), 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(7, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 2;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS43Key:
+ case kHS43Ufo:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(Common::Point(3, 7), 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead();
+ break;
+ case GRAB_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(Common::Point(3, 7), 0, 67515, 1);
+ gnap._actionStatus = 1;
+ break;
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS43WalkArea1:
+ case kHS43WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO) && (_vm->_toyUfoActionStatus == 5 || _vm->_toyUfoActionStatus == -1)) {
+ _vm->_toyUfoActionStatus = 5;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4] && (!_vm->isFlag(kGFGnapControlsToyUFO) || !_vm->isFlag(kGFGroceryStoreHatTaken))) {
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextTwoHeadedGuySequenceId == -1) {
+ switch (_vm->getRandom(5)) {
+ case 0:
+ _nextTwoHeadedGuySequenceId = 0x13C;
+ break;
+ case 1:
+ _nextTwoHeadedGuySequenceId = 0x134;
+ break;
+ case 2:
+ _nextTwoHeadedGuySequenceId = 0x135;
+ break;
+ case 3:
+ _nextTwoHeadedGuySequenceId = 0x136;
+ break;
+ case 4:
+ _nextTwoHeadedGuySequenceId = 0x13A;
+ break;
+ }
+ if (_nextTwoHeadedGuySequenceId == _currTwoHeadedGuySequenceId)
+ _nextTwoHeadedGuySequenceId = -1;
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ if (_vm->_newSceneNum == 54)
+ _vm->clearFlag(kGFGnapControlsToyUFO);
+}
+
+void Scene43::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ switch (gnap._actionStatus) {
+ case 0:
+ gameSys.setAnimation(0, 0, 0);
+ _vm->_sceneDone = true;
+ break;
+
+ case 1:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ _vm->_timers[2] = _vm->getRandom(30) + 20;
+ _vm->_timers[3] = _vm->getRandom(50) + 200;
+ gameSys.insertSequence(0x13D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x13D;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x13D, gnap._id, 0);
+ _nextTwoHeadedGuySequenceId = 0x13B;
+ gameSys.insertSequence(0x13B, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2);
+ _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId;
+ _nextTwoHeadedGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ gnap._actionStatus = -1;
+ }
+ break;
+
+ default:
+ gameSys.setAnimation(0, 0, 0);
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_currTwoHeadedGuySequenceId == 0x13A) {
+ if (_vm->isFlag(kGFGroceryStoreHatTaken)) {
+ _nextTwoHeadedGuySequenceId = 0x13E;
+ _vm->stopSound(0x108F6);
+ } else if (_vm->getRandom(2) != 0) {
+ _nextTwoHeadedGuySequenceId = 0x137;
+ } else {
+ _nextTwoHeadedGuySequenceId = 0x138;
+ }
+ } else if (_currTwoHeadedGuySequenceId == 0x13E) {
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 54;
+ }
+ if (_nextTwoHeadedGuySequenceId != -1) {
+ gameSys.insertSequence(_nextTwoHeadedGuySequenceId, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2);
+ _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId;
+ _nextTwoHeadedGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(100) + 100;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 4:
+ _vm->_sceneDone = true;
+ _vm->_toyUfoActionStatus = -1;
+ break;
+ case 6:
+ gameSys.insertSequence(0x10871, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ gameSys.removeSequence(0x1086F, 1, true);
+ _vm->setFlag(kGFUnk14);
+ updateHotspots();
+ _vm->toyUfoSetStatus(kGFUnk18);
+ _vm->_toyUfoSequenceId = 0x871;
+ gameSys.setAnimation(0x10871, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoX = 96;
+ _vm->_toyUfoY = 131;
+ break;
+ case 7:
+ gameSys.insertSequence(0x10874, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0);
+ _vm->_toyUfoSequenceId = 0x874;
+ gameSys.setAnimation(0x10874, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = 8;
+ _vm->setFlag(kGFJointTaken);
+ gnap._actionStatus = 3;
+ break;
+ case 8:
+ _nextTwoHeadedGuySequenceId = 0x13A;
+ _vm->_toyUfoX = 514;
+ _vm->_toyUfoY = 125;
+ _vm->toyUfoFlyTo(835, 125, 0, 835, 0, 300, 3);
+ _vm->_toyUfoActionStatus = 9;
+ break;
+ case 9:
+ // Nothing
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ _vm->_toyUfoActionStatus = -1;
+ break;
+ }
+ }
+}
+
+/*****************************************************************************/
+
+Scene44::Scene44(GnapEngine *vm) : Scene(vm) {
+ _nextSpringGuySequenceId = -1;
+ _nextKissingLadySequenceId = -1;
+ _currSpringGuySequenceId = -1;
+ _currKissingLadySequenceId = -1;
+}
+
+int Scene44::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ return 0xFF;
+}
+
+void Scene44::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS44UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS44UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setDeviceHotspot(kHS44UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS44ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS44ExitUfo, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS44ExitShow, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS44KissingLady, 300, 160, 400, 315, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7);
+ _vm->setHotspot(kHS44Spring, 580, 310, 635, 375, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS44SpringGuy, 610, 375, 690, 515, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8);
+ _vm->setHotspot(kHS44WalkArea1, 0, 0, 800, 445);
+ _vm->setHotspot(kHS44WalkArea2, 617, 0, 800, 600);
+ _vm->setDeviceHotspot(kHS44Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk13))
+ _vm->_hotspots[kHS44KissingLady]._flags = SF_DISABLED;
+ if (_vm->isFlag(kGFSpringTaken))
+ _vm->_hotspots[kHS44Spring]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 10;
+ }
+}
+
+void Scene44::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0xF7, 0, 0, 0, kSeqLoop, 0, 0, 0);
+ gameSys.insertSequence(0xFC, 256, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFSpringTaken))
+ _currSpringGuySequenceId = 0xF8;
+ else
+ _currSpringGuySequenceId = 0xF9;
+
+ _nextSpringGuySequenceId = -1;
+ gameSys.setAnimation(_currSpringGuySequenceId, 1, 4);
+ gameSys.insertSequence(_currSpringGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFUnk13)) {
+ if (_vm->_prevSceneNum != 50 || _vm->_sceneSavegameLoaded) {
+ _currKissingLadySequenceId = 0xF6;
+ _nextKissingLadySequenceId = -1;
+ } else {
+ _vm->setGrabCursorSprite(kItemGum);
+ _currKissingLadySequenceId = 0xF5;
+ _nextKissingLadySequenceId = 0xF6;
+ gameSys.setAnimation(0xF5, 1, 2);
+ }
+ } else {
+ _currKissingLadySequenceId = 0xEC;
+ _nextKissingLadySequenceId = -1;
+ gameSys.setAnimation(0xEC, 1, 2);
+ }
+
+ gameSys.insertSequence(_currKissingLadySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 43)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else {
+ switch (_vm->_prevSceneNum) {
+ case 43:
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 7, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ break;
+ case 46:
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(7, 8), -1, 0x107D2, 1);
+ break;
+ case 50:
+ gnap.initPos(4, 8, kDirBottomRight);
+ if (_vm->_sceneSavegameLoaded) {
+ plat.initPos(_vm->_hotspotsWalkPos[4].x, _vm->_hotspotsWalkPos[4].y, kDirIdleRight);
+ } else if (!_vm->isFlag(kGFUnk13)) {
+ _vm->_timers[0] = 50;
+ _vm->_timers[1] = 20;
+ plat._pos = Common::Point(5, 8);
+ plat._sequenceId = 0xFD;
+ plat._idleFacing = kDirIdleLeft;
+ plat._id = 160;
+ plat._sequenceDatNum = 0;
+ gameSys.insertSequence(0xFD, 160, 0, 0, kSeqNone, 0, 0, 0);
+ }
+ _vm->endSceneInit();
+ break;
+ default:
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1);
+ break;
+ }
+ }
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS44UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 6;
+ _vm->_newSceneNum = 43;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3);
+ }
+ break;
+
+ case kHS44UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 6;
+ _vm->_newSceneNum = 46;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3);
+ }
+ break;
+
+ case kHS44UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ break;
+ }
+ } else if (_vm->_sceneClickedHotspot <= 9) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS44Device:
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ break;
+
+ case kHS44Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS44ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitUfoParty], 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS44ExitUfo:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 43;
+ break;
+
+ case kHS44ExitShow:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitShow], 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 46;
+ break;
+
+ case kHS44KissingLady:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap._actionStatus = 2;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, -1, 9);
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, _vm->_hotspotsWalkPos[kHS44KissingLady].x - 1, _vm->_hotspotsWalkPos[kHS44KissingLady].y);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(4, 3));
+ break;
+ case GRAB_CURSOR:
+ gnap.playImpossible();
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 1;
+ break;
+ case PLAT_CURSOR:
+ gnap.useDeviceOnPlatypus();
+ plat.walkTo(Common::Point(6, 7), 1, 0x107D2, 1);
+ if (gnap._pos == Common::Point(7, 7))
+ gnap.walkStep();
+ gnap.playIdle(Common::Point(5, 7));
+ plat._actionStatus = 4;
+ break;
+ }
+ }
+ break;
+
+ case kHS44Spring:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44Spring], 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case GRAB_CURSOR:
+ gnap.playPullOutDevice(Common::Point(8, 0));
+ gnap.playUseDevice(Common::Point(8, 0));
+ _nextSpringGuySequenceId = 0xFB;
+ _vm->invAdd(kItemSpring);
+ _vm->setFlag(kGFSpringTaken);
+ updateHotspots();
+ break;
+ case TALK_CURSOR:
+ gnap.playImpossible();
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS44SpringGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44SpringGuy], 8, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ if (_vm->isFlag(kGFSpringTaken))
+ gnap.playMoan1(Common::Point(8, 7));
+ else
+ gnap.playScratchingHead(Common::Point(8, 7));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS44SpringGuy], -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS44WalkArea1:
+ case kHS44WalkArea2:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 7;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO) && _currKissingLadySequenceId != 0xF5)
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextKissingLadySequenceId == -1) {
+ switch (_vm->getRandom(20)) {
+ case 0:
+ _nextKissingLadySequenceId = 0xED;
+ break;
+ case 1:
+ _nextKissingLadySequenceId = 0xEE;
+ break;
+ case 2:
+ _nextKissingLadySequenceId = 0xF0;
+ break;
+ case 3:
+ _nextKissingLadySequenceId = 0xF3;
+ break;
+ case 4:
+ _nextKissingLadySequenceId = 0xF4;
+ break;
+ default:
+ _nextKissingLadySequenceId = 0xEC;
+ break;
+ }
+ if (_nextKissingLadySequenceId != 0xEC && _nextKissingLadySequenceId == _currKissingLadySequenceId)
+ _nextKissingLadySequenceId = -1;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(20) + 20;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSpringGuySequenceId == -1) {
+ if (_vm->getRandom(5) != 0) {
+ if (!_vm->isFlag(kGFSpringTaken))
+ _nextSpringGuySequenceId = 0xF9;
+ } else {
+ if (_vm->isFlag(kGFSpringTaken))
+ _nextSpringGuySequenceId = 0xF8;
+ else
+ _nextSpringGuySequenceId = 0xFA;
+ }
+ }
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene44::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _nextKissingLadySequenceId = 0xEF;
+ break;
+ case 2:
+ _nextKissingLadySequenceId = 0xF2;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ switch (plat._actionStatus) {
+ case 4:
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.insertSequence(0xFE, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0);
+ plat._sequenceId = 0xFE;
+ plat._sequenceDatNum = 0;
+ gameSys.setAnimation(0xFE, plat._id, 1);
+ gameSys.removeSequence(_currKissingLadySequenceId, 1, true);
+ plat._actionStatus = 5;
+ }
+ break;
+ case 5:
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 50;
+ break;
+ default:
+ plat._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ if (_nextKissingLadySequenceId == 0xF6) {
+ gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ plat.initPos(5, 8, kDirIdleLeft);
+ _currKissingLadySequenceId = _nextKissingLadySequenceId;
+ _nextKissingLadySequenceId = -1;
+ gameSys.setAnimation(0, 0, 2);
+ } else if (_nextKissingLadySequenceId != -1) {
+ gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextKissingLadySequenceId, 1, 2);
+ _currKissingLadySequenceId = _nextKissingLadySequenceId;
+ _nextKissingLadySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(20) + 20;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2) {
+ if (_currSpringGuySequenceId == 0xFB) {
+ _vm->setGrabCursorSprite(kItemSpring);
+ _nextSpringGuySequenceId = 0xF8;
+ }
+ if (_nextSpringGuySequenceId != -1) {
+ gameSys.insertSequence(_nextSpringGuySequenceId, 1, _currSpringGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextSpringGuySequenceId, 1, 4);
+ _currSpringGuySequenceId = _nextSpringGuySequenceId;
+ _nextSpringGuySequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(20) + 20;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 6:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene45::Scene45(GnapEngine *vm) : Scene(vm) {
+ _currDancerSequenceId = -1;
+}
+
+int Scene45::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 4);
+ gameSys.setAnimation(0, 0, 5);
+ return _vm->isFlag(kGFUnk23) ? 0xA2 : 0xA1;
+}
+
+void Scene45::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS45UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS45UfoExitRight, 794, 0, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED);
+ _vm->setDeviceHotspot(kHS45UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS45ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS45ExitShoe, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS45ExitRight, 794, 100, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED, 10, 8);
+ _vm->setHotspot(kHS45ExitDiscoBall, 200, 0, 600, 10, SF_DISABLED);
+ _vm->setHotspot(kHS45DiscoBall, 370, 10, 470, 125, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7);
+ _vm->setHotspot(kHS45WalkArea1, 0, 0, 800, 472);
+ _vm->setDeviceHotspot(kHS45Device, -1, -1, -1, -1);
+ if (_vm->isFlag(kGFUnk22)) {
+ _vm->_hotspots[kHS45Platypus]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitUfoParty]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitShoe]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitRight]._flags = SF_DISABLED;
+ _vm->_hotspots[kHS45ExitDiscoBall]._flags = SF_EXIT_U_CURSOR;
+ }
+ if (_vm->isFlag(kGFUnk23) || _vm->isFlag(kGFUnk22))
+ _vm->_hotspots[kHS45DiscoBall]._flags = SF_DISABLED;
+ _vm->_hotspotsCount = 8;
+ }
+}
+
+void Scene45::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (!_vm->isSoundPlaying(0x1094A))
+ _vm->playSound(0x1094A, true);
+
+ _vm->queueInsertDeviceIcon();
+
+ gameSys.insertSequence(0x96, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ _currDancerSequenceId = 0x8F;
+ gameSys.setAnimation(_currDancerSequenceId, 1, 2);
+ gameSys.insertSequence(_currDancerSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 46)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 5);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else if (_vm->isFlag(kGFUnk22)) {
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gnap._id = 1;
+ gameSys.setAnimation(0x9E, 1, 0);
+ gnap._actionStatus = 1;
+ gameSys.insertSequence(gnap._sequenceId, gnap._id, 0, 0, kSeqNone, 0, 0, 0);
+ plat.initPos(4, 8, kDirIdleLeft);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 46) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 41) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(11, 9, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1);
+ gnap.walkTo(Common::Point(10, 9), -1, 0x107BA, 1);
+ } else {
+ gnap.initPos(2, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1);
+ }
+
+ if (!_vm->isFlag(kGFUnk21) && !_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setFlag(kGFUnk21);
+ _vm->setGrabCursorSprite(-1);
+ gameSys.setAnimation(0x9D, gnap._id, 0);
+ gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) {
+ _vm->gameUpdateTick();
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ int newSeqId = _vm->getRandom(7) + 0x8F;
+ gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(newSeqId, 1, 2);
+ _currDancerSequenceId = newSeqId;
+ }
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ }
+ }
+ gnap._sequenceId = 0x9D;
+ gnap._sequenceDatNum = 0;
+ _vm->hideCursor();
+ _vm->addFullScreenSprite(0x8A, 255);
+ gameSys.setAnimation(0xA0, 256, 0);
+ gameSys.insertSequence(0xA0, 256, 0, 0, kSeqNone, 0, 0, 0);
+ while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone)
+ _vm->gameUpdateTick();
+ gameSys.setAnimation(0x107BD, gnap._id, 0);
+ gameSys.insertSequence(0x107BD, gnap._id,
+ makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id,
+ kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY);
+ _vm->removeFullScreenSprite();
+ _vm->showCursor();
+ gnap._sequenceId = 0x7BD;
+ gnap._sequenceDatNum = 1;
+ }
+
+ plat.playSequence(0x9A);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094A))
+ _vm->playSound(0x1094A, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS45UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 2;
+ _vm->_newSceneNum = 46;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 5);
+ }
+ break;
+
+ case kHS45UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 2;
+ _vm->_newSceneNum = 41;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 5);
+ }
+ break;
+
+ case kHS45UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS45Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS45Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ plat.playSequence(0x9A);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS45ExitUfoParty:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS45ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ }
+ break;
+
+ case kHS45ExitShoe:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 46;
+ }
+ break;
+
+ case kHS45ExitRight:
+ if (gnap._actionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, plat._pos.y), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 41;
+ }
+ break;
+
+ case kHS45ExitDiscoBall:
+ _vm->clearFlag(kGFUnk22);
+ _vm->setFlag(kGFUnk23);
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 54;
+ break;
+
+ case kHS45DiscoBall:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex == kItemSpring) {
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS45DiscoBall], 0, 0x9F, 5);
+ gnap._actionStatus = 1;
+ _vm->setGrabCursorSprite(-1);
+ _vm->invRemove(kItemSpring);
+ } else if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playScratchingHead(Common::Point(5, 0));
+ break;
+ case GRAB_CURSOR:
+ case TALK_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS45WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 3;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 5);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene && gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+
+ _vm->_sceneWaiting = false;
+}
+
+void Scene45::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _vm->_sceneWaiting = true;
+ _vm->setFlag(kGFUnk22);
+ updateHotspots();
+ gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0);
+ gnap._sequenceId = 0x9E;
+ gnap._sequenceDatNum = 0;
+ gameSys.setAnimation(0x9E, gnap._id, 0);
+ break;
+ default:
+ gnap._actionStatus = -1;
+ break;
+ }
+ }
+
+ if (gameSys.getAnimationStatus(1) == 2) {
+ gameSys.setAnimation(0, 0, 1);
+ if (_vm->getRandom(2) != 0)
+ plat.playSequence(0x9B);
+ else
+ plat.playSequence(0x9C);
+ gameSys.setAnimation(plat._sequenceId, plat._id, 1);
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ gameSys.setAnimation(0, 0, 2);
+ int newSeqId = _vm->getRandom(7) + 0x8F;
+ gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(newSeqId, 1, 2);
+ _currDancerSequenceId = newSeqId;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) {
+ gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x96, 1, 3);
+ gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(0x99, 1, 4);
+ }
+
+ if (gameSys.getAnimationStatus(5) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 2:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 5);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+/*****************************************************************************/
+
+Scene46::Scene46(GnapEngine *vm) : Scene(vm) {
+ _currSackGuySequenceId = -1;
+ _nextItchyGuySequenceId = -1;
+ _nextSackGuySequenceId = -1;
+ _currItchyGuySequenceId = -1;
+}
+
+int Scene46::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ gameSys.setAnimation(0, 0, 2);
+ gameSys.setAnimation(0, 0, 3);
+ gameSys.setAnimation(0, 0, 4);
+ return 0x4E;
+}
+
+void Scene46::updateHotspots() {
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_DISABLED);
+ _vm->setHotspot(kHS46UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR);
+ _vm->setHotspot(kHS46UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR);
+ _vm->setDeviceHotspot(kHS46UfoDevice, -1, 534, -1, 599);
+ _vm->_hotspotsCount = 4;
+ } else {
+ _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS46ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9);
+ _vm->setHotspot(kHS46ExitKissinBooth, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8);
+ _vm->setHotspot(kHS46ExitDisco, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8);
+ _vm->setHotspot(kHS46SackGuy, 180, 370, 235, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8);
+ _vm->setHotspot(kHS46ItchyGuy, 535, 210, 650, 480, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8);
+ _vm->setHotspot(kHS46WalkArea1, 0, 0, 800, 485);
+ _vm->setDeviceHotspot(kHS46Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 8;
+ }
+}
+
+void Scene46::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ PlayerPlat& plat = *_vm->_plat;
+
+ _vm->queueInsertDeviceIcon();
+ gameSys.insertSequence(0x4D, 0, 0, 0, kSeqLoop, 0, 0, 0);
+
+ _currSackGuySequenceId = 0x4B;
+ _nextSackGuySequenceId = -1;
+ gameSys.setAnimation(0x4B, 1, 3);
+ gameSys.insertSequence(_currSackGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ _currItchyGuySequenceId = 0x47;
+ _nextItchyGuySequenceId = -1;
+ gameSys.setAnimation(0x47, 1, 4);
+ gameSys.insertSequence(_currItchyGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoId = 0;
+ _vm->_toyUfoActionStatus = -1;
+ _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId();
+ _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId;
+ if (_vm->_prevSceneNum == 44)
+ _vm->_toyUfoX = 30;
+ else
+ _vm->_toyUfoX = 770;
+ gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->endSceneInit();
+ } else if (_vm->_prevSceneNum == 44) {
+ gnap.initPos(-1, 8, kDirUpRight);
+ plat.initPos(-1, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1);
+ } else if (_vm->_prevSceneNum == 45) {
+ gnap.initPos(11, 8, kDirUpRight);
+ plat.initPos(12, 8, kDirUpLeft);
+ _vm->endSceneInit();
+ gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1);
+ plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1);
+ } else {
+ gnap.initPos(5, 11, kDirUpRight);
+ plat.initPos(6, 11, kDirUpLeft);
+ _vm->endSceneInit();
+ plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1);
+ gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1);
+ }
+
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+
+ while (!_vm->_sceneDone) {
+ if (!_vm->isSoundPlaying(0x1094B))
+ _vm->playSound(0x1094B, true);
+
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS46UfoExitLeft:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 3;
+ _vm->_newSceneNum = 44;
+ _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2);
+ }
+ break;
+
+ case kHS46UfoExitRight:
+ if (_vm->_toyUfoActionStatus < 0) {
+ _vm->_isLeavingScene = true;
+ _vm->_toyUfoActionStatus = 3;
+ _vm->_newSceneNum = 45;
+ _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2);
+ }
+ break;
+
+ case kHS46UfoDevice:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+ }
+ } else {
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS46Device:
+ _vm->runMenu();
+ updateHotspots();
+ break;
+
+ case kHS46Platypus:
+ if (gnap._actionStatus < 0) {
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playImpossible(plat._pos);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(plat._pos);
+ break;
+ case GRAB_CURSOR:
+ gnap.kissPlatypus(0);
+ break;
+ case TALK_CURSOR:
+ gnap.playBrainPulsating(plat._pos);
+ plat.playSequence(plat.getSequenceId());
+ break;
+ case PLAT_CURSOR:
+ gnap.playImpossible(plat._pos);
+ break;
+ }
+ }
+ }
+ break;
+
+ case kHS46SackGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46SackGuy], 2, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46SackGuy].x + 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpLeft;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS46SackGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 2;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS46ItchyGuy:
+ if (_vm->_grabCursorSpriteIndex >= 0) {
+ gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 7, 0);
+ } else {
+ switch (_vm->_verbCursor) {
+ case LOOK_CURSOR:
+ gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46ItchyGuy].x - 1, 0));
+ break;
+ case TALK_CURSOR:
+ gnap._idleFacing = kDirUpRight;
+ gnap.walkTo(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1);
+ gnap._actionStatus = 1;
+ break;
+ case GRAB_CURSOR:
+ case PLAT_CURSOR:
+ gnap.playImpossible();
+ break;
+ }
+ }
+ break;
+
+ case kHS46ExitUfoParty:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS46ExitUfoParty].y), 0, 0x107AE, 1);
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 40;
+ break;
+
+ case kHS46ExitKissinBooth:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, gnap._pos.y), 0, 0x107AF, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, plat._pos.y), -1, 0x107CF, 1);
+ _vm->_newSceneNum = 44;
+ break;
+
+ case kHS46ExitDisco:
+ _vm->_isLeavingScene = true;
+ gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, gnap._pos.y), 0, 0x107AB, 1);
+ gnap._actionStatus = 0;
+ plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, plat._pos.y), -1, 0x107CD, 1);
+ _vm->_newSceneNum = 45;
+ break;
+
+ case kHS46WalkArea1:
+ if (gnap._actionStatus < 0)
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ break;
+ }
+ }
+
+ if (_vm->_mouseClickState._left && gnap._actionStatus < 0) {
+ _vm->_mouseClickState._left = false;
+ if (_vm->isFlag(kGFGnapControlsToyUFO)) {
+ _vm->_toyUfoActionStatus = 4;
+ _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2);
+ } else {
+ gnap.walkTo(Common::Point(-1, -1), -1, -1, 1);
+ }
+ }
+
+ updateAnimations();
+ _vm->toyUfoCheckTimer();
+
+ if (!_vm->_isLeavingScene) {
+ if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ plat.updateIdleSequence();
+ if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO))
+ gnap.updateIdleSequence();
+ if (!_vm->_timers[4]) {
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextItchyGuySequenceId == -1) {
+ if (_vm->getRandom(2) != 0)
+ _nextItchyGuySequenceId = 0x49;
+ else
+ _nextItchyGuySequenceId = 0x48;
+ }
+ }
+ if (!_vm->_timers[5]) {
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+ if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSackGuySequenceId == -1)
+ _nextSackGuySequenceId = 0x4C;
+ }
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+
+ _vm->gameUpdateTick();
+ }
+}
+
+void Scene46::updateAnimations() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (gameSys.getAnimationStatus(0) == 2) {
+ gameSys.setAnimation(0, 0, 0);
+ switch (gnap._actionStatus) {
+ case 0:
+ _vm->_sceneDone = true;
+ break;
+ case 1:
+ _nextItchyGuySequenceId = 0x46;
+ break;
+ case 2:
+ _nextSackGuySequenceId = 0x4A;
+ break;
+ }
+ gnap._actionStatus = -1;
+ }
+
+ if (gameSys.getAnimationStatus(3) == 2 && _nextSackGuySequenceId != -1) {
+ gameSys.insertSequence(_nextSackGuySequenceId, 1, _currSackGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextSackGuySequenceId, 1, 3);
+ _currSackGuySequenceId = _nextSackGuySequenceId;
+ _nextSackGuySequenceId = -1;
+ _vm->_timers[5] = _vm->getRandom(50) + 80;
+ }
+
+ if (gameSys.getAnimationStatus(4) == 2 && _nextItchyGuySequenceId != -1) {
+ gameSys.insertSequence(_nextItchyGuySequenceId, 1, _currItchyGuySequenceId, 1, kSeqSyncWait, 0, 0, 0);
+ gameSys.setAnimation(_nextItchyGuySequenceId, 1, 4);
+ _currItchyGuySequenceId = _nextItchyGuySequenceId;
+ _nextItchyGuySequenceId = -1;
+ _vm->_timers[4] = _vm->getRandom(50) + 80;
+ }
+
+ if (gameSys.getAnimationStatus(2) == 2) {
+ switch (_vm->_toyUfoActionStatus) {
+ case 3:
+ _vm->_sceneDone = true;
+ break;
+ default:
+ _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId();
+ gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1,
+ _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId,
+ kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128);
+ _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId;
+ ++_vm->_toyUfoId;
+ gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2);
+ break;
+ }
+ _vm->_toyUfoActionStatus = -1;
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group4.h b/engines/gnap/scenes/group4.h
new file mode 100644
index 0000000000..afcd62e9e7
--- /dev/null
+++ b/engines/gnap/scenes/group4.h
@@ -0,0 +1,298 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GROUP4_H
+#define GNAP_GROUP4_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+enum {
+ kHS40Platypus = 0,
+ kHS40ExitCave = 1,
+ kHS40ExitToyStand = 2,
+ kHS40ExitBBQ = 3,
+ kHS40ExitUfo = 4,
+ kHS40ExitKissinBooth = 5,
+ kHS40ExitDancefloor = 6,
+ kHS40ExitShoe = 7,
+ kHS40Device = 8
+};
+
+enum {
+ kHS41Platypus = 0,
+ kHS41ExitCave = 1,
+ kHS41Exit = 2,
+ kHS41ExitBBQ = 3,
+ kHS41ToyVendor = 4,
+ kHS41Kid = 5,
+ kHS41ToyUfo = 6,
+ kHS41Device = 7,
+ kHS41WalkArea1 = 8
+};
+
+enum {
+ kHS41UfoExitLeft = 1,
+ kHS41UfoExitRight = 2,
+ kHS41UfoDevice = 3,
+ kHS41UfoWalkArea1 = 4
+};
+
+enum {
+ kHS42Platypus = 0,
+ kHS42ExitUfoParty = 1,
+ kHS42ExitToyStand = 2,
+ kHS42ExitUfo = 3,
+ kHS42BBQVendor = 4,
+ kHS42ChickenLeg = 5,
+ kHS42Device = 6,
+ kHS42WalkArea1 = 7,
+ kHS42WalkArea2 = 8
+};
+
+enum {
+ kHS42UfoExitLeft = 1,
+ kHS42UfoExitRight = 2,
+ kHS42UfoHotSauce = 3,
+ kHS42UfoDevice = 4
+};
+
+enum {
+ kHS43Platypus = 0,
+ kHS43Device = 1,
+ kHS43ExitUfoParty = 2,
+ kHS43ExitBBQ = 3,
+ kHS43ExitKissinBooth = 4,
+ kHS43TwoHeadedGuy = 5,
+ kHS43Key = 6,
+ kHS43Ufo = 7,
+ kHS43WalkArea1 = 8,
+ kHS43WalkArea2 = 9
+};
+
+enum {
+ kHS43UfoExitLeft = 1,
+ kHS43UfoExitRight = 2,
+ kHS43UfoKey = 3,
+ kHS43UfoBucket = 4,
+ kHS43UfoDevice = 5
+};
+
+enum {
+ kHS44Platypus = 0,
+ kHS44ExitUfoParty = 1,
+ kHS44ExitUfo = 2,
+ kHS44ExitShow = 3,
+ kHS44KissingLady = 4,
+ kHS44Spring = 5,
+ kHS44SpringGuy = 6,
+ kHS44Device = 7,
+ kHS44WalkArea1 = 8,
+ kHS44WalkArea2 = 9
+};
+
+enum {
+ kHS44UfoExitLeft = 1,
+ kHS44UfoExitRight = 2,
+ kHS44UfoDevice = 3
+};
+
+enum {
+ kHS45Platypus = 0,
+ kHS45ExitUfoParty = 1,
+ kHS45ExitShoe = 2,
+ kHS45ExitRight = 3,
+ kHS45ExitDiscoBall = 4,
+ kHS45DiscoBall = 5,
+ kHS45Device = 6,
+ kHS45WalkArea1 = 7
+};
+
+enum {
+ kHS45UfoExitLeft = 1,
+ kHS45UfoExitRight = 2,
+ kHS45UfoDevice = 3
+};
+
+enum {
+ kHS46Platypus = 0,
+ kHS46ExitUfoParty = 1,
+ kHS46ExitKissinBooth = 2,
+ kHS46ExitDisco = 3,
+ kHS46SackGuy = 4,
+ kHS46ItchyGuy = 5,
+ kHS46Device = 6,
+ kHS46WalkArea1 = 7
+};
+
+enum {
+ kHS46UfoExitLeft = 1,
+ kHS46UfoExitRight = 2,
+ kHS46UfoDevice = 3
+};
+
+enum {
+ kAS41LeaveScene = 0,
+ kAS41UseQuarterWithToyVendor = 1,
+ kAS41TalkToyVendor = 2,
+ kAS41UseGumWithToyUfo = 3,
+ kAS41UseChickenBucketWithKid = 4,
+ kAS41GrabKid = 5,
+ kAS41GiveBackToyUfo = 6,
+ kAS41ToyUfoLeaveScene = 7,
+ kAS41ToyUfoRefresh = 8,
+ kAS41UfoGumAttached = 9
+};
+
+enum {
+ kAS42LeaveScene = 0,
+ kAS42TalkBBQVendor = 1,
+ kAS42UseQuarterWithBBQVendor = 2,
+ kAS42UseQuarterWithBBQVendorDone = 3,
+ kAS42GrabChickenLeg = 4,
+ kAS42ToyUfoLeaveScene = 5,
+ kAS42ToyUfoRefresh = 6,
+ kAS42ToyUfoPickUpHotSauce = 7
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+class CutScene;
+
+class Scene40: public Scene {
+public:
+ Scene40(GnapEngine *vm);
+ virtual ~Scene40() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+};
+
+class Scene41: public Scene {
+public:
+ Scene41(GnapEngine *vm);
+ virtual ~Scene41() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currKidSequenceId;
+ int _nextKidSequenceId;
+ int _currToyVendorSequenceId;
+ int _nextToyVendorSequenceId;
+};
+
+class Scene42: public Scene {
+public:
+ Scene42(GnapEngine *vm);
+ virtual ~Scene42() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currBBQVendorSequenceId;
+ int _nextBBQVendorSequenceId;
+};
+
+class Scene43: public Scene {
+public:
+ Scene43(GnapEngine *vm);
+ virtual ~Scene43() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currTwoHeadedGuySequenceId;
+ int _nextTwoHeadedGuySequenceId;
+};
+
+class Scene44: public Scene {
+public:
+ Scene44(GnapEngine *vm);
+ virtual ~Scene44() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _nextSpringGuySequenceId;
+ int _nextKissingLadySequenceId;
+ int _currSpringGuySequenceId;
+ int _currKissingLadySequenceId;
+};
+
+class Scene45: public Scene {
+public:
+ Scene45(GnapEngine *vm);
+ virtual ~Scene45() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currDancerSequenceId;
+};
+
+class Scene46: public Scene {
+public:
+ Scene46(GnapEngine *vm);
+ virtual ~Scene46() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations();
+ virtual void updateAnimationsCb() {};
+
+private:
+ int _currSackGuySequenceId;
+ int _nextItchyGuySequenceId;
+ int _nextSackGuySequenceId;
+ int _currItchyGuySequenceId;
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_GROUP4_H
diff --git a/engines/gnap/scenes/group5.cpp b/engines/gnap/scenes/group5.cpp
new file mode 100644
index 0000000000..46f4c51e5d
--- /dev/null
+++ b/engines/gnap/scenes/group5.cpp
@@ -0,0 +1,381 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/group5.h"
+
+namespace Gnap {
+
+Scene53::Scene53(GnapEngine *vm) : Scene(vm) {
+ _isGnapPhoning = false;
+ _currHandSequenceId = -1;
+ _callsMadeCtr = 0;
+ _callsRndUsed = 0;
+}
+
+int Scene53::init() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ gameSys.setAnimation(0, 0, 0);
+ gameSys.setAnimation(0, 0, 1);
+ return 0x75;
+}
+
+void Scene53::updateHotspots() {
+ _vm->setHotspot(kHS53Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey1, 336, 238, 361, 270, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey2, 376, 243, 405, 274, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey3, 415, 248, 441, 276, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey4, 329, 276, 358, 303, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey5, 378, 282, 408, 311, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey6, 417, 286, 446, 319, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey7, 332, 311, 361, 342, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey8, 376, 318, 407, 349, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey9, 417, 320, 447, 353, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKey0, 377, 352, 405, 384, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKeySharp, 419, 358, 450, 394, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneKeyStar, 328, 346, 359, 379, SF_GRAB_CURSOR);
+ _vm->setHotspot(kHS53PhoneExit, 150, 585, 650, 600, SF_EXIT_D_CURSOR);
+
+ _vm->setDeviceHotspot(kHS53Device, -1, -1, -1, -1);
+ _vm->_hotspotsCount = 15;
+}
+
+int Scene53::pressPhoneNumberButton(int phoneNumber, int buttonNum) {
+ static const int kGnapHandSequenceIds[13] = {
+ 0x00,
+ 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x4F
+ };
+
+ static const int kPlatypusHandSequenceIds[13] = {
+ 0x00,
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5B
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ if (_isGnapPhoning) {
+ gameSys.setAnimation(kGnapHandSequenceIds[buttonNum], 40, 6);
+ gameSys.insertSequence(kGnapHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = kGnapHandSequenceIds[buttonNum];
+ } else {
+ gameSys.setAnimation(kPlatypusHandSequenceIds[buttonNum], 40, 6);
+ gameSys.insertSequence(kPlatypusHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = kPlatypusHandSequenceIds[buttonNum];
+ }
+
+ gnap._actionStatus = 6;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+
+ if (buttonNum < 11)
+ phoneNumber = buttonNum % 10 + 10 * phoneNumber;
+
+ return phoneNumber;
+}
+
+int Scene53::getRandomCallIndex() {
+ int index, tries = 0;
+ if (_callsRndUsed == 0x7FFF)
+ _callsRndUsed = 0;
+ do {
+ index = _vm->getRandom(16);
+ if (++tries == 300)
+ _callsRndUsed = 0;
+ } while (_callsRndUsed & (1 << index));
+ _callsRndUsed |= (1 << index);
+ return index;
+}
+
+void Scene53::runRandomCall() {
+ static const int kCallSequenceIds[15] = {
+ 0x60, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x6B, 0x6C, 0x6D, 0x71
+ };
+
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ ++_callsMadeCtr;
+ if (_callsMadeCtr <= 10) {
+ int index;
+
+ do {
+ index = getRandomCallIndex();
+ } while (!_isGnapPhoning && (index == 0 || index == 3 || index == 4 || index == 11));
+ gameSys.setAnimation(kCallSequenceIds[index], 1, 6);
+ gameSys.insertSequence(kCallSequenceIds[index], 1, 0, 0, kSeqNone, 16, 0, 0);
+ } else {
+ gameSys.setAnimation(0x74, 1, 6);
+ gameSys.insertSequence(0x74, 1, 0, 0, kSeqNone, 16, 0, 0);
+ _callsMadeCtr = 0;
+ }
+
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+}
+
+void Scene53::runChitChatLine() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+ bool flag = false;
+ int sequenceId = -1;
+
+ gameSys.setAnimation(0x6E, 1, 6);
+ gameSys.insertSequence(0x6E, 1, 0, 0, kSeqNone, 16, 0, 0);
+
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = 0x45;
+ } else {
+ gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ _currHandSequenceId = 0x5E;
+ }
+
+ _vm->_hotspots[kHS53Device]._flags = SF_DISABLED;
+
+ while (!flag) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case 2:
+ sequenceId = 0x6F;
+ flag = 1;
+ break;
+ case 3:
+ sequenceId = 0x70;
+ flag = 1;
+ break;
+ case 4:
+ sequenceId = 0x71;
+ flag = 1;
+ break;
+ case 14:
+ sequenceId = -1;
+ flag = 1;
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 17;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ break;
+ }
+
+ if (flag && sequenceId != -1) {
+ _vm->stopSound(0xA0);
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ gnap._actionStatus = 1;
+ gameSys.setAnimation(sequenceId, 1, 6);
+ gameSys.insertSequence(sequenceId, 1, 0, 0, kSeqNone, 16, 0, 0);
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+ gameSys.setAnimation(0x72, 1, 6);
+ gameSys.insertSequence(0x72, 1, 0, 0, kSeqNone, 16, 0, 0);
+ gnap._actionStatus = 1;
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ gnap._actionStatus = -1;
+ }
+ }
+
+ updateHotspots();
+
+ gnap._actionStatus = 1;
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+}
+
+void Scene53::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+ PlayerGnap& gnap = *_vm->_gnap;
+
+ int phoneNumber = 0;
+ int phoneNumberLen = 0;
+
+ _vm->queueInsertDeviceIcon();
+
+ if (_vm->isFlag(kGFSpringTaken)) {
+ _currHandSequenceId = 0x45;
+ _isGnapPhoning = true;
+ } else {
+ _currHandSequenceId = 0x5E;
+ _isGnapPhoning = false;
+ }
+
+ gameSys.insertSequence(_currHandSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0);
+ _vm->endSceneInit();
+ _vm->setVerbCursor(GRAB_CURSOR);
+ _vm->playSound(0xA0, true);
+
+ while (!_vm->_sceneDone) {
+ _vm->updateMouseCursor();
+ _vm->updateCursorByHotspot();
+
+ _vm->testWalk(0, 0, -1, -1, -1, -1);
+
+ _vm->_sceneClickedHotspot = _vm->getClickedHotspotId();
+ _vm->updateGrabCursorSprite(0, 0);
+
+ switch (_vm->_sceneClickedHotspot) {
+ case kHS53Device:
+ if (gnap._actionStatus < 0) {
+ _vm->runMenu();
+ updateHotspots();
+ }
+ break;
+ case kHS53PhoneKey1:
+ case kHS53PhoneKey2:
+ case kHS53PhoneKey3:
+ case kHS53PhoneKey4:
+ case kHS53PhoneKey5:
+ case kHS53PhoneKey6:
+ case kHS53PhoneKey7:
+ case kHS53PhoneKey8:
+ case kHS53PhoneKey9:
+ case kHS53PhoneKey0:
+ _vm->stopSound(0xA0);
+ ++phoneNumberLen;
+ phoneNumber = pressPhoneNumberButton(phoneNumber, _vm->_sceneClickedHotspot - 1);
+ debugC(kDebugBasic, "phoneNumber: %d", phoneNumber);
+ if (phoneNumberLen == 7) {
+ gnap._actionStatus = 1;
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+ if (phoneNumber == 7284141) {
+ runChitChatLine();
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ } else if (phoneNumber != 5556789 || _vm->isFlag(kGFPictureTaken)) {
+ runRandomCall();
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ } else {
+ phoneNumber = 0;
+ phoneNumberLen = 0;
+ _vm->_sceneDone = true;
+ _vm->_newSceneNum = 17;
+ if (_isGnapPhoning)
+ _vm->setFlag(kGFUnk25);
+ else
+ _vm->setFlag(kGFPlatypusTalkingToAssistant);
+ }
+ }
+ break;
+ case kHS53PhoneKeySharp:
+ case kHS53PhoneKeyStar:
+ pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1);
+ break;
+ case kHS53PhoneExit:
+ if (gnap._actionStatus < 0) {
+ gnap._actionStatus = 1;
+ if (_vm->isFlag(kGFSpringTaken)) {
+ gameSys.setAnimation(0x73, 40, 6);
+ gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0);
+ while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) {
+ _vm->updateMouseCursor();
+ _vm->gameUpdateTick();
+ }
+ _currHandSequenceId = 0x73;
+ gnap._actionStatus = -1;
+ }
+ _vm->_isLeavingScene = true;
+ _vm->_sceneDone = true;
+ gnap._actionStatus = 0;
+ _vm->_newSceneNum = 17;
+ }
+ break;
+ }
+
+ _vm->checkGameKeys();
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE);
+ _vm->runMenu();
+ updateHotspots();
+ }
+ _vm->gameUpdateTick();
+ }
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/group5.h b/engines/gnap/scenes/group5.h
new file mode 100644
index 0000000000..dd238ec65c
--- /dev/null
+++ b/engines/gnap/scenes/group5.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.
+ *
+ */
+
+#ifndef GNAP_GROUP5_H
+#define GNAP_GROUP5_H
+
+#include "gnap/debugger.h"
+#include "gnap/scenes/scenecore.h"
+
+namespace Gnap {
+
+enum {
+ kHS53Platypus = 0,
+ kHS53Device = 1,
+ kHS53PhoneKey1 = 2,
+ kHS53PhoneKey2 = 3,
+ kHS53PhoneKey3 = 4,
+ kHS53PhoneKey4 = 5,
+ kHS53PhoneKey5 = 6,
+ kHS53PhoneKey6 = 7,
+ kHS53PhoneKey7 = 8,
+ kHS53PhoneKey8 = 9,
+ kHS53PhoneKey9 = 10,
+ kHS53PhoneKey0 = 11,
+ kHS53PhoneKeySharp = 12,
+ kHS53PhoneKeyStar = 13,
+ kHS53PhoneExit = 14
+};
+
+/*****************************************************************************/
+
+class GnapEngine;
+
+class Scene53: public Scene {
+public:
+ Scene53(GnapEngine *vm);
+ virtual ~Scene53() {}
+
+ virtual int init();
+ virtual void updateHotspots();
+ virtual void run();
+ virtual void updateAnimations() {};
+ virtual void updateAnimationsCb() {};
+
+private:
+ bool _isGnapPhoning;
+ int _currHandSequenceId;
+ int _callsMadeCtr;
+ uint _callsRndUsed;
+
+ int pressPhoneNumberButton(int phoneNumber, int buttonNum);
+ int getRandomCallIndex();
+ void runRandomCall();
+ void runChitChatLine();
+};
+
+} // End of namespace Gnap
+#endif // GNAP_GROUP5_H
diff --git a/engines/gnap/scenes/groupcs.cpp b/engines/gnap/scenes/groupcs.cpp
new file mode 100644
index 0000000000..c096eae27c
--- /dev/null
+++ b/engines/gnap/scenes/groupcs.cpp
@@ -0,0 +1,430 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/groupcs.h"
+
+
+namespace Gnap {
+
+Scene16::Scene16(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene16::init() {
+ _sequenceIdArr[0] = 0x1F2;
+ _sequenceIdArr[1] = 0x201;
+ _sequenceIdArr[2] = 0x1FC;
+ _sequenceIdArr[3] = 0x1F4;
+ _sequenceIdArr[4] = 0x1FB;
+ _sequenceIdArr[5] = 0x1F0;
+ _sequenceIdArr[6] = 0x1FD;
+ _sequenceIdArr[7] = 0x1FE;
+ _sequenceIdArr[8] = 0x1F7;
+ _sequenceIdArr[9] = 0x1F9;
+ _sequenceIdArr[10] = 0x1F8;
+ _sequenceIdArr[11] = 0x1F1;
+ _sequenceIdArr[12] = 0x202;
+ _sequenceIdArr[13] = 0x1F6;
+ _sequenceIdArr[14] = 0x1F3;
+ _sequenceIdArr[15] = 0x1FA;
+ _sequenceIdArr[16] = 0x1FF;
+ _sequenceIdArr[17] = 0x200;
+ _sequenceIdArr[18] = 0x203;
+ _sequenceIdArr[19] = 0x206;
+ _sequenceIdArr[20] = 0x207;
+ _sequenceIdArr[21] = 0x204;
+ _sequenceIdArr[22] = 0x205;
+ _resourceIdArr[0] = 0x1C;
+ _resourceIdArr[1] = 2;
+ _resourceIdArr[2] = 0x1B;
+ _resourceIdArr[3] = 0;
+ _resourceIdArr[4] = 0x167;
+ _resourceIdArr[5] = 1;
+ _resourceIdArr[6] = 0x15B;
+ _resourceIdArr[7] = 0x15A;
+ _resourceIdArr[8] = 0x170;
+ _resourceIdArr[9] = 0x1EB;
+ _resourceIdArr[10] = 0x1EC;
+ _resourceIdArr[11] = 0x1BE;
+ _resourceIdArr[12] = 0x1BF;
+ _sequenceCountArr[0] = 4;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 6;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 3;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _itemsCount = 13;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene471::Scene471(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene471::init() {
+ _sequenceIdArr[0] = 0x301;
+ _sequenceIdArr[1] = 0x305;
+ _sequenceIdArr[2] = 0x302;
+ _sequenceIdArr[3] = 0x304;
+ _sequenceIdArr[4] = 0x300;
+ _resourceIdArr[0] = 3;
+ _resourceIdArr[1] = 0;
+ _resourceIdArr[2] = 1;
+ _resourceIdArr[3] = 0;
+ _resourceIdArr[4] = 2;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+Scene472::Scene472(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene472::init() {
+ _sequenceIdArr[0] = 0x306;
+ _sequenceIdArr[1] = 0x309;
+ _sequenceIdArr[2] = 0x307;
+ _sequenceIdArr[3] = 0x308;
+ _sequenceIdArr[4] = 0x30A;
+ _resourceIdArr[0] = 0x8E;
+ _resourceIdArr[1] = 0x90;
+ _resourceIdArr[2] = 0x8F;
+ _resourceIdArr[3] = 0x91;
+ _sequenceCountArr[0] = 2;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _itemsCount = 4;
+
+ return -1;
+}
+
+Scene473::Scene473(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene473::init() {
+ _sequenceIdArr[0] = 0x320;
+ _sequenceIdArr[1] = 0x321;
+ _resourceIdArr[0] = 0x142;
+ _resourceIdArr[1] = 0x143;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _itemsCount = 2;
+
+ return -1;
+}
+
+Scene474::Scene474(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene474::init() {
+ _sequenceIdArr[0] = 0x30C;
+ _sequenceIdArr[1] = 0x30D;
+ _sequenceIdArr[2] = 0x30B;
+ _resourceIdArr[0] = 0x142;
+ _resourceIdArr[1] = 0x141;
+ _resourceIdArr[2] = 0x177;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _itemsCount = 3;
+
+ return -1;
+}
+
+Scene475::Scene475(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene475::init() {
+ _sequenceIdArr[0] = 0x30E;
+ _sequenceIdArr[1] = 0x30F;
+ _sequenceIdArr[2] = 0x310;
+ _sequenceIdArr[3] = 0x311;
+ _resourceIdArr[0] = 0x206;
+ _resourceIdArr[1] = 0x207;
+ _sequenceCountArr[0] = 3;
+ _sequenceCountArr[1] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _itemsCount = 2;
+
+ return -1;
+}
+
+Scene476::Scene476(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene476::init() {
+ _sequenceIdArr[0] = 0x31E;
+ _sequenceIdArr[1] = 0x31F;
+ _resourceIdArr[0] = 0x2FA;
+ _sequenceCountArr[0] = 2;
+ _canSkip[0] = false;
+ _itemsCount = 1;
+
+ return -1;
+}
+
+Scene477::Scene477(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene477::init() {
+ int v0, v4, v2, v3;
+
+ _sequenceIdArr[0] = 0x316;
+ _sequenceIdArr[1] = 0x31A;
+ _sequenceIdArr[2] = 0x314;
+ _sequenceIdArr[3] = 0x31B;
+ int v1 = 4;
+ if (!_vm->isFlag(kGFTwigTaken)) {
+ _sequenceIdArr[4] = 0x31C;
+ v1 = 5;
+ }
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _sequenceIdArr[v1++] = 0x31D;
+ v4 = v1;
+ _sequenceIdArr[v1] = 0x319;
+ v0 = v1 + 1;
+ v3 = v0;
+ _sequenceIdArr[v0++] = 0x317;
+ _sequenceIdArr[v0++] = 0x312;
+ _sequenceIdArr[v0] = 0x31A;
+ v2 = v0 + 1;
+ if (!_vm->isFlag(kGFTwigTaken))
+ _sequenceIdArr[v2++] = 0x31C;
+ if (!_vm->isFlag(kGFPlatypusTalkingToAssistant))
+ _sequenceIdArr[v2++] = 0x31D;
+ _sequenceIdArr[v2] = 0x313;
+ _sequenceIdArr[v2 + 1] = 0x315;
+ _resourceIdArr[0] = 0x2B8;
+ _resourceIdArr[1] = 0x20C;
+ _resourceIdArr[2] = 0x2B8;
+ _resourceIdArr[3] = 0x20B;
+ _resourceIdArr[4] = 0x20B;
+ _sequenceCountArr[0] = v4;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = v2 - v3;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene48::Scene48(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene48::init() {
+ _sequenceIdArr[0] = 390;
+ _sequenceIdArr[1] = 391;
+ _sequenceIdArr[2] = 392;
+ _sequenceIdArr[3] = 393;
+ _sequenceIdArr[4] = 394;
+ _sequenceIdArr[5] = 395;
+ _sequenceIdArr[6] = 396;
+ _sequenceIdArr[7] = 397;
+ _sequenceIdArr[8] = 398;
+ _sequenceIdArr[9] = 399;
+ _sequenceIdArr[10] = 400;
+ _sequenceIdArr[11] = 401;
+ _sequenceIdArr[12] = 402;
+ _resourceIdArr[0] = 238;
+ _resourceIdArr[1] = 42;
+ _resourceIdArr[2] = 2;
+ _resourceIdArr[3] = 37;
+ _resourceIdArr[4] = 35;
+ _resourceIdArr[5] = 38;
+ _resourceIdArr[6] = 39;
+ _resourceIdArr[7] = 40;
+ _resourceIdArr[8] = 41;
+ _resourceIdArr[9] = 36;
+ _resourceIdArr[10] = 41;
+ _resourceIdArr[11] = 388;
+ _resourceIdArr[12] = 387;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 1;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _canSkip[5] = false;
+ _canSkip[6] = false;
+ _canSkip[7] = false;
+ _canSkip[8] = false;
+ _canSkip[9] = false;
+ _canSkip[10] = false;
+ _canSkip[11] = false;
+ _canSkip[12] = false;
+ _itemsCount = 13;
+
+ return -1;
+}
+
+/*****************************************************************************/
+
+Scene541::Scene541(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene541::init() {
+ _sequenceIdArr[0] = 0x1BE;
+ _sequenceIdArr[1] = 0x1BF;
+ _sequenceIdArr[2] = 0x1BA;
+ _sequenceIdArr[3] = 0x1BB;
+ _sequenceIdArr[4] = 0x1BD;
+ _sequenceIdArr[5] = 0x1BC;
+ _resourceIdArr[0] = 0x3C;
+ _resourceIdArr[1] = 0x43;
+ _resourceIdArr[2] = 0x44;
+ if (_vm->isFlag(kGFPictureTaken))
+ _resourceIdArr[3] = 0x47;
+ else
+ _resourceIdArr[3] = 0x46;
+ _resourceIdArr[4] = 0x45;
+ _sequenceCountArr[0] = 1;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 1;
+ _sequenceCountArr[3] = 2;
+ _sequenceCountArr[4] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _itemsCount = 5;
+
+ return -1;
+}
+
+Scene542::Scene542(GnapEngine *vm) : CutScene(vm) {}
+
+int Scene542::init() {
+ _sequenceIdArr[0] = 0x1C9;
+ _sequenceIdArr[1] = 0x1C7;
+ _sequenceIdArr[2] = 0x1CC;
+ _sequenceIdArr[3] = 0x1C8;
+ _sequenceIdArr[4] = 0x1CB;
+ _sequenceIdArr[5] = 0x1C0;
+ _sequenceIdArr[6] = 0x1CA;
+ _sequenceIdArr[7] = 0x1CE;
+ _sequenceIdArr[8] = 0x1CD;
+ _sequenceIdArr[9] = 0x1C1;
+ _sequenceIdArr[10] = 0x1C2;
+ _sequenceIdArr[11] = 0x1C3;
+ _sequenceIdArr[12] = 0x1C4;
+ _sequenceIdArr[13] = 0x1C6;
+ _sequenceIdArr[14] = 0x1C5;
+ _sequenceIdArr[15] = 0x1D0;
+ _sequenceIdArr[16] = 0x1D0;
+ _sequenceIdArr[17] = 0x1D0;
+ _resourceIdArr[0] = 0xD5;
+ _resourceIdArr[1] = 0x14C;
+ _resourceIdArr[2] = 0xD5;
+ _resourceIdArr[3] = 0xBF;
+ _resourceIdArr[4] = 0xD6;
+ _resourceIdArr[5] = 0x154;
+ _resourceIdArr[6] = 0x155;
+ _resourceIdArr[7] = 0xB9;
+ _resourceIdArr[8] = 0xBA;
+ _resourceIdArr[9] = 0x17B;
+ _resourceIdArr[10] = 0x17A;
+ _resourceIdArr[11] = 0x17C;
+ _resourceIdArr[12] = 0x17A;
+ _resourceIdArr[13] = 0x1B7;
+ _resourceIdArr[14] = 0x1B8;
+ _resourceIdArr[15] = 0x1B9;
+ _sequenceCountArr[0] = 2;
+ _sequenceCountArr[1] = 1;
+ _sequenceCountArr[2] = 2;
+ _sequenceCountArr[3] = 1;
+ _sequenceCountArr[4] = 1;
+ _sequenceCountArr[5] = 1;
+ _sequenceCountArr[6] = 1;
+ _sequenceCountArr[7] = 1;
+ _sequenceCountArr[8] = 1;
+ _sequenceCountArr[9] = 1;
+ _sequenceCountArr[10] = 1;
+ _sequenceCountArr[11] = 1;
+ _sequenceCountArr[12] = 1;
+ _sequenceCountArr[13] = 1;
+ _sequenceCountArr[14] = 1;
+ _sequenceCountArr[15] = 1;
+ _canSkip[0] = false;
+ _canSkip[1] = false;
+ _canSkip[2] = false;
+ _canSkip[3] = false;
+ _canSkip[4] = false;
+ _canSkip[5] = false;
+ _canSkip[6] = false;
+ _canSkip[7] = false;
+ _canSkip[8] = false;
+ _canSkip[9] = false;
+ _canSkip[10] = false;
+ _canSkip[11] = false;
+ _canSkip[12] = false;
+ _canSkip[13] = true;
+ _canSkip[14] = true;
+ _canSkip[15] = false;
+ _itemsCount = 16;
+
+ return -1;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/groupcs.h b/engines/gnap/scenes/groupcs.h
new file mode 100644
index 0000000000..58033564ce
--- /dev/null
+++ b/engines/gnap/scenes/groupcs.h
@@ -0,0 +1,122 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_GROUPCS_H
+#define GNAP_GROUPCS_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+class CutScene;
+
+class Scene16: public CutScene {
+public:
+ Scene16(GnapEngine *vm);
+ virtual ~Scene16() {}
+
+ virtual int init();
+};
+
+class Scene471: public CutScene {
+public:
+ Scene471(GnapEngine *vm);
+ virtual ~Scene471() {}
+
+ virtual int init();
+};
+
+class Scene472: public CutScene {
+public:
+ Scene472(GnapEngine *vm);
+ virtual ~Scene472() {}
+
+ virtual int init();
+};
+
+class Scene473: public CutScene {
+public:
+ Scene473(GnapEngine *vm);
+ virtual ~Scene473() {}
+
+ virtual int init();
+};
+
+class Scene474: public CutScene {
+public:
+ Scene474(GnapEngine *vm);
+ virtual ~Scene474() {}
+
+ virtual int init();
+};
+
+class Scene475: public CutScene {
+public:
+ Scene475(GnapEngine *vm);
+ virtual ~Scene475() {}
+
+ virtual int init();
+};
+
+class Scene476: public CutScene {
+public:
+ Scene476(GnapEngine *vm);
+ virtual ~Scene476() {}
+
+ virtual int init();
+};
+
+class Scene477: public CutScene {
+public:
+ Scene477(GnapEngine *vm);
+ virtual ~Scene477() {}
+
+ virtual int init();
+};
+
+class Scene48: public CutScene {
+public:
+ Scene48(GnapEngine *vm);
+ virtual ~Scene48() {}
+
+ virtual int init();
+};
+
+class Scene541: public CutScene {
+public:
+ Scene541(GnapEngine *vm);
+ virtual ~Scene541() {}
+
+ virtual int init();
+};
+
+class Scene542: public CutScene {
+public:
+ Scene542(GnapEngine *vm);
+ virtual ~Scene542() {}
+
+ virtual int init();
+};
+} // End of namespace Gnap
+
+#endif // GNAP_GROUPCS_H
diff --git a/engines/gnap/scenes/intro.cpp b/engines/gnap/scenes/intro.cpp
new file mode 100644
index 0000000000..5bb2239bab
--- /dev/null
+++ b/engines/gnap/scenes/intro.cpp
@@ -0,0 +1,184 @@
+/* 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.
+ *
+ */
+
+#include "video/avi_decoder.h"
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+#include "gnap/scenes/intro.h"
+
+namespace Gnap {
+
+SceneIntro::SceneIntro(GnapEngine *vm) : Scene(vm) {
+}
+
+int SceneIntro::init() {
+ return 0x37C;
+}
+
+void SceneIntro::run() {
+ const int animIdArr[] = {
+ 0x356, 0x357, 0x358, 0x35A, 0x35F,
+ 0x360, 0x361, 0x362, 0x363, 0x364,
+ 0x365, 0x368, 0x369, 0x36B, 0x378,
+ 0x36C, 0x36D, 0x36E, 0x36F, 0x370,
+ 0x371, 0x372, 0x373, 0x374, 0x375,
+ 0x376, 0x377, 0x378, 0x379, 0x37A,
+ 0x37B, 0};
+
+ const int backgroundIdArr[] = {
+ 0x354, 0x355, 0, 1, 3,
+ 4, 5, 6, 7, 8,
+ 7, 9, 0xA, 0xB, 0xC,
+ 0xD, 0xE, 0xF, 0x10, 0x11,
+ 0x12, 0x13, 0x17, 0x14, 0x19,
+ 0x1A, 0x14, 0x15, 0x16, 0x14,
+ 0x19, 0};
+
+ GameSys& gameSys = *_vm->_gameSys;
+ int index = 0;
+ bool skip = false;
+
+ _vm->hideCursor();
+ _vm->_dat->open(1, "musop_n.dat");
+
+ Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
+ if (!videoDecoder->loadFile("hoffman.avi")) {
+ delete videoDecoder;
+ warning("Unable to open video 'hoffman.avi' - Skipping intro");
+ return;
+ }
+ videoDecoder->start();
+
+ int vidPosX = (800 - videoDecoder->getWidth()) / 2;
+ int vidPosY = (600 - videoDecoder->getHeight()) / 2;
+ bool skipVideo = false;
+
+ _vm->screenEffect(1, 255, 255, 255);
+
+ while (!_vm->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ if (frame->format.bytesPerPixel == 1) {
+ _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, vidPosX, vidPosY, frame->w, frame->h);
+ } else if (frame->format.bytesPerPixel != 4) {
+ Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat());
+ _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ } else {
+ Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat());
+
+ // The intro AVI is played upside down, it's the only video played in the English version
+ for (uint16 y = 0; y < frame1->h / 2; y++) {
+ uint32 *ptrFrom = (uint32 *)frame1->getBasePtr(0, y);
+ uint32 *ptrTo = (uint32 *)frame1->getBasePtr(0, frame1->h - y - 1);
+ // in this else branch, bytesPerPixel equals 4
+ for (uint16 x = 0; x < frame1->pitch / 4; x++) {
+ uint32 t = *ptrFrom;
+ *ptrFrom = *ptrTo;
+ *ptrTo = t;
+ ptrFrom++;
+ ptrTo++;
+ }
+ }
+
+ _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ }
+ _vm->_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) ||
+ event.type == Common::EVENT_LBUTTONUP)
+ skipVideo = true;
+ }
+
+ _vm->_system->delayMillis(10);
+ }
+
+ delete videoDecoder;
+
+ gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]);
+ gameSys.insertSequence(0x356, 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(0x356, 2, 0);
+
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ if (gameSys.getAnimationStatus(0) == 2 || skip ) {
+ skip = false;
+ gameSys.requestClear2(false);
+ gameSys.requestClear1();
+ if ( index == 11 || index == 1 )
+ _vm->screenEffect(0, 0, 0, 0);
+
+ gameSys.setAnimation(0, 0, 0);
+ if (++index >= 31)
+ _vm->_sceneDone = true;
+ else {
+ gameSys.insertSequence(animIdArr[index], 2, 0, 0, kSeqNone, 0, 0, 0);
+ if (index == 2) {
+ _vm->playSound(0x10000, false);
+ gameSys.insertSequence(0x359, 2, 0, 0, 0, 0, 0, 0);
+ } else if (index == 3)
+ gameSys.insertSequence(0x35B, 2, 0, 0, kSeqNone, 0, 0, 0);
+ else if (index == 12)
+ gameSys.insertSequence(0x36A, 2, 0, 0, kSeqNone, 0, 0, 0);
+
+ gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]);
+ gameSys.setAnimation(animIdArr[index], 2, 0);
+
+ if (index == 11)
+ _vm->stopSound(0x10000);
+ }
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ if (index == 0) {
+ skip = true;
+ _vm->stopSound(0x3CF);
+ } else if (index == 1)
+ skip = true;
+ else
+ _vm->_sceneDone = true;
+ }
+ }
+
+ _vm->stopSound(0x10000);
+
+ _vm->_newSceneNum = 1;
+ _vm->_newCursorValue = 1;
+
+ _vm->_dat->open(1, "stock_n.dat");
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/intro.h b/engines/gnap/scenes/intro.h
new file mode 100644
index 0000000000..15aedfc4fc
--- /dev/null
+++ b/engines/gnap/scenes/intro.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_INTRO_H
+#define GNAP_INTRO_H
+
+#include "gnap/debugger.h"
+#include "gnap/scenes/scenecore.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class SceneIntro: public Scene {
+public:
+ SceneIntro(GnapEngine *vm);
+ virtual ~SceneIntro() {}
+
+ virtual int init();
+ virtual void updateHotspots() {}
+ virtual void run();
+ virtual void updateAnimations() {}
+ virtual void updateAnimationsCb() {}
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_INTRO_H
diff --git a/engines/gnap/scenes/scenecore.cpp b/engines/gnap/scenes/scenecore.cpp
new file mode 100644
index 0000000000..fb6f91c954
--- /dev/null
+++ b/engines/gnap/scenes/scenecore.cpp
@@ -0,0 +1,740 @@
+/* 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.
+ *
+ */
+
+#include "gnap/gnap.h"
+#include "gnap/gamesys.h"
+#include "gnap/resource.h"
+
+#include "gnap/scenes/scenecore.h"
+
+#include "gnap/scenes/arcade.h"
+#include "gnap/scenes/groupcs.h"
+#include "gnap/scenes/group0.h"
+#include "gnap/scenes/group1.h"
+#include "gnap/scenes/group2.h"
+#include "gnap/scenes/group3.h"
+#include "gnap/scenes/group4.h"
+#include "gnap/scenes/group5.h"
+#include "gnap/scenes/intro.h"
+
+namespace Gnap {
+
+int GnapEngine::initSceneLogic() {
+ int backgroundId = -1;
+
+ switch (_currentSceneNum) {
+ case 0:
+ _scene = new SceneIntro(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 1:
+ _scene = new Scene01(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 2:
+ _scene = new Scene02(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 3:
+ _scene = new Scene03(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 4:
+ _scene = new Scene04(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 5:
+ _scene = new Scene05(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 6:
+ _scene = new Scene06(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 7:
+ _scene = new Scene07(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 8:
+ _scene = new Scene08(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 9:
+ _scene = new Scene09(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 10:
+ _scene = new Scene10(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 11:
+ _scene = new Scene11(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 12:
+ _scene = new Scene12(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 13:
+ _scene = new Scene13(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 14:
+ _scene = new Scene14(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 15:
+ _scene = new Scene15(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 16:
+ case 47:
+ case 48:
+ case 54:
+ backgroundId = -1;
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ break;
+ case 17:
+ _scene = new Scene17(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 18:
+ _scene = new Scene18(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ _scene->updateHotspots();
+ break;
+ case 19:
+ _scene = new Scene19(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 20:
+ _scene = new Scene20(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 21:
+ _scene = new Scene21(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 22:
+ _scene = new Scene22(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 23:
+ _scene = new Scene23(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 24:
+ _scene = new Scene24(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 136, 11, 10);
+ break;
+ case 25:
+ _scene = new Scene25(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 26:
+ _scene = new Scene26(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 27:
+ _scene = new Scene27(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 28:
+ _scene = new Scene28(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 29:
+ _scene = new Scene29(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 30:
+ _scene = new Scene30(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 31:
+ _scene = new Scene31(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 32:
+ _scene = new Scene32(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 33:
+ _scene = new Scene33(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 34:
+ _scene = new Scene03(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 35:
+ _scene = new Scene05(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 36:
+ _scene = new Scene06(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 37:
+ _scene = new Scene04(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 38:
+ _scene = new Scene38(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 39:
+ _scene = new Scene39(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 40:
+ _scene = new Scene40(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 41:
+ _scene = new Scene41(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 42:
+ _scene = new Scene42(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 43:
+ _scene = new Scene43(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 44:
+ _scene = new Scene44(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 45:
+ _scene = new Scene45(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 46:
+ _scene = new Scene46(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 49:
+ _scene = new Scene49(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 50:
+ _scene = new Scene50(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 51:
+ _scene = new Scene51(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 52:
+ _scene = new Scene52(this);
+ backgroundId = _scene->init();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ case 53:
+ _scene = new Scene53(this);
+ backgroundId = _scene->init();
+ _scene->updateHotspots();
+ _gameSys->setScaleValues(0, 500, 1, 1000);
+ initSceneGrid(21, 146, 11, 10);
+ break;
+ }
+
+ return backgroundId;
+}
+
+void GnapEngine::runSceneLogic() {
+ switch (_currentSceneNum) {
+ case 0:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 8;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 4;
+ break;
+ case 7:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 8;
+ break;
+ case 8:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 9;
+ break;
+ case 9:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 10;
+ break;
+ case 10:
+ case 12:
+ case 13:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 11;
+ break;
+ case 11:
+ case 15:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 12;
+ break;
+ case 14:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 13;
+ break;
+ case 16:
+ _scene = new Scene16(this);
+ _scene->init();
+ _newSceneNum = 17;
+ _newCursorValue = 3;
+ _scene->run();
+ delete _scene;
+ break;
+ case 17:
+ case 18:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 20;
+ break;
+ case 19:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 19;
+ break;
+ case 20:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 22;
+ break;
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 37;
+ break;
+ case 47:
+ if (_prevSceneNum == 49) {
+ _scene = new Scene471(this);
+ _scene->init();
+ _newSceneNum = 7;
+ _newCursorValue = 2;
+ } else if (_prevSceneNum == 13) {
+ _scene = new Scene472(this);
+ _scene->init();
+ _newSceneNum = 11;
+ } else if (!isFlag(kGFPlatypusDisguised) && _prevSceneNum == 2) {//CHECKME
+ if (isFlag(kGFUnk25)) {
+ _scene = new Scene473(this);
+ _scene->init();
+ _newSceneNum = 2;
+ } else {
+ _scene = new Scene474(this);
+ _scene->init();
+ _newSceneNum = 49;
+ }
+ } else if (_prevSceneNum == 21) {
+ _scene = new Scene475(this);
+ _scene->init();
+ _newSceneNum = 21;
+ setFlag(kGFTwigTaken);
+ setFlag(kGFKeysTaken);
+ } else if (_prevSceneNum == 30) {
+ _scene = new Scene476(this);
+ _scene->init();
+ _newSceneNum = 26;
+ } else if (isFlag(kGFPlatypusDisguised) && _cursorValue == 1) {
+ _scene = new Scene477(this);
+ _scene->init();
+ _newSceneNum = 4;
+ }
+ _scene->run();
+ delete _scene;
+ break;
+ case 48:
+ _scene = new Scene48(this);
+ _scene->init();
+ _newSceneNum = 33;
+ _newCursorValue = 4;
+ _scene->run();
+ delete _scene;
+ break;
+ case 49:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 47;
+ break;
+ case 50:
+ _scene->run();
+ delete _scene;
+ _newSceneNum = _prevSceneNum;
+ break;
+ case 51:
+ _scene->run();
+ delete _scene;
+ break;
+ case 52:
+ _scene->run();
+ delete _scene;
+ _newSceneNum = _prevSceneNum;
+ break;
+ case 53:
+ _scene->run();
+ delete _scene;
+ if (_newSceneNum == 55)
+ _newSceneNum = 53;
+ break;
+ case 54:
+ if (_prevSceneNum == 45) {
+ _scene = new Scene541(this);
+ _scene->init();
+ _newSceneNum = 43;
+ _scene->run();
+ delete _scene;
+ } else {
+ _scene = new Scene542(this);
+ _scene->init();
+ _scene->run();
+ delete _scene;
+ _gameDone = true;
+ }
+ break;
+ }
+}
+
+void Scene::playRandomSound(int timerIndex) {
+ if (!_vm->_timers[timerIndex]) {
+ _vm->_timers[timerIndex] = _vm->getRandom(40) + 50;
+ switch (_vm->getRandom(4)) {
+ case 0:
+ _vm->playSound(0x1091B, false);
+ break;
+ case 1:
+ _vm->playSound(0x10921, false);
+ break;
+ case 2:
+ _vm->playSound(0x10927, false);
+ break;
+ case 3:
+ _vm->playSound(0x1091D, false);
+ break;
+ }
+ }
+}
+
+bool Scene::clearKeyStatus() {
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_UP);
+ _vm->clearKeyStatus1(Common::KEYCODE_RIGHT);
+ _vm->clearKeyStatus1(Common::KEYCODE_LEFT);
+ _vm->clearKeyStatus1(Common::KEYCODE_p);
+ return true;
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_p)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_p);
+ _vm->pauseGame();
+ _vm->updatePause();
+ }
+
+ return false;
+}
+
+/****************************************************************************/
+
+CutScene::CutScene(GnapEngine *vm) : Scene(vm) {
+ _itemsCount = -1;
+
+ for (int i = 0; i < 16; i++) {
+ _resourceIdArr[i] = -1;
+ _sequenceCountArr[i] = -1;
+ _canSkip[i] = false;
+ }
+
+ for (int i = 0; i < 50; i++)
+ _sequenceIdArr[i] = -1;
+}
+
+void CutScene::run() {
+ GameSys& gameSys = *_vm->_gameSys;
+
+ int itemIndex = 0;
+ int soundId = -1;
+ int volume = 100;
+ int duration = 0;
+ bool skip = false;
+
+ if (_vm->_prevSceneNum == 2) {
+ soundId = 0x36B;
+ duration = MAX(1, 300 / _vm->getSequenceTotalDuration(_sequenceIdArr[_itemsCount - 1]));
+ _vm->_timers[0] = 0;
+ }
+
+ if (soundId != -1)
+ _vm->playSound(soundId, false);
+
+ _vm->hideCursor();
+
+ gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[0]);
+
+ for (int j = 0; j < _sequenceCountArr[0]; ++j)
+ gameSys.insertSequence(_sequenceIdArr[j], j + 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.setAnimation(_sequenceIdArr[0], 2, 0);
+
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+
+ _vm->_mouseClickState._left = false;
+
+ int firstSequenceIndex = 0;
+ while (!_vm->_sceneDone) {
+ _vm->gameUpdateTick();
+
+ if (gameSys.getAnimationStatus(0) == 2 || skip) {
+ skip = false;
+ gameSys.requestClear2(false);
+ gameSys.requestClear1();
+ gameSys.setAnimation(0, 0, 0);
+ firstSequenceIndex += _sequenceCountArr[itemIndex++];
+ if (itemIndex >= _itemsCount) {
+ _vm->_sceneDone = true;
+ } else {
+ for (int m = 0; m < _sequenceCountArr[itemIndex]; ++m)
+ gameSys.insertSequence(_sequenceIdArr[firstSequenceIndex + m], m + 2, 0, 0, kSeqNone, 0, 0, 0);
+ gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[itemIndex]);
+ gameSys.setAnimation(_sequenceIdArr[firstSequenceIndex], 2, 0);
+ }
+ }
+
+ if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) {
+ _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE);
+ _vm->clearKeyStatus1(Common::KEYCODE_SPACE);
+ _vm->clearKeyStatus1(Common::KEYCODE_RETURN);
+ if (_canSkip[itemIndex])
+ skip = true;
+ else
+ _vm->_sceneDone = true;
+ }
+
+ if (!_vm->_timers[0] && itemIndex == _itemsCount - 1) {
+ _vm->_timers[0] = 2;
+ volume = MAX(1, volume - duration);
+ _vm->setSoundVolume(soundId, volume);
+ }
+ }
+
+ if (soundId != -1)
+ _vm->stopSound(soundId);
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/scenes/scenecore.h b/engines/gnap/scenes/scenecore.h
new file mode 100644
index 0000000000..c54b5a7bc5
--- /dev/null
+++ b/engines/gnap/scenes/scenecore.h
@@ -0,0 +1,70 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_SCENECORE_H
+#define GNAP_SCENECORE_H
+
+#include "gnap/debugger.h"
+
+namespace Gnap {
+
+class GnapEngine;
+
+class Scene {
+public:
+ Scene(GnapEngine *vm) : _vm(vm) {};
+ virtual ~Scene() {};
+
+ void playRandomSound(int timerIndex);
+ bool clearKeyStatus();
+
+ virtual int init() = 0;
+ virtual void updateHotspots() = 0;
+ virtual void run() = 0;
+ virtual void updateAnimations() = 0;
+ virtual void updateAnimationsCb() = 0;
+
+protected:
+ GnapEngine *_vm;
+};
+
+class CutScene : public Scene {
+public:
+ CutScene(GnapEngine *vm);
+ virtual ~CutScene() {};
+
+ virtual int init() = 0;
+ void updateHotspots() {}
+ void run();
+ void updateAnimations() {}
+ void updateAnimationsCb() {}
+
+protected:
+ int _itemsCount;
+ int _resourceIdArr[16];
+ int _sequenceCountArr[16];
+ int _sequenceIdArr[50];
+ bool _canSkip[16];
+};
+} // End of namespace Gnap
+
+#endif // GNAP_SCENECORE_H
diff --git a/engines/gnap/sound.cpp b/engines/gnap/sound.cpp
new file mode 100644
index 0000000000..b09cc7cafe
--- /dev/null
+++ b/engines/gnap/sound.cpp
@@ -0,0 +1,102 @@
+/* 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.
+ *
+ */
+
+#include "gnap/sound.h"
+#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
+
+namespace Gnap {
+
+SoundMan::SoundMan(GnapEngine *vm) : _vm(vm) {
+}
+
+SoundMan::~SoundMan() {
+}
+
+void SoundMan::playSound(int resourceId, bool looping) {
+ SoundItem soundItem;
+ soundItem._resourceId = resourceId;
+
+ SoundResource *soundResource = _vm->_soundCache->get(resourceId);
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(soundResource->_data, soundResource->_size, DisposeAfterUse::NO);
+ Audio::AudioStream *audioStream = Audio::makeLoopingAudioStream(Audio::makeWAVStream(stream, DisposeAfterUse::YES), looping ? 0 : 1);
+
+ _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &soundItem._handle, audioStream);
+
+ _items.push_back(soundItem);
+
+}
+
+void SoundMan::stopSound(int resourceId) {
+ const int index = find(resourceId);
+ if (index < 0)
+ return;
+
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _vm->_mixer->stopHandle(_items[index]._handle);
+ _items.remove_at(index);
+}
+
+void SoundMan::setSoundVolume(int resourceId, int volume) {
+ if (resourceId == -1 || volume < 0 || volume > 100)
+ return;
+
+ const int index = find(resourceId);
+ if (index < 0)
+ return;
+
+ int realVol = volume * 2.55;
+ _vm->_mixer->setChannelVolume(_items[index]._handle, realVol);
+}
+
+bool SoundMan::isSoundPlaying(int resourceId) {
+ const int index = find(resourceId);
+ if (index < 0)
+ return false;
+
+ return _vm->_mixer->isSoundHandleActive(_items[index]._handle);
+}
+
+void SoundMan::stopAll() {
+ for (int index = 0; index < (int)_items.size(); ++index) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _vm->_mixer->stopHandle(_items[index]._handle);
+ }
+}
+
+void SoundMan::update() {
+ for (int index = 0; index < (int)_items.size(); ++index)
+ if (!_vm->_mixer->isSoundHandleActive(_items[index]._handle)) {
+ _vm->_soundCache->release(_items[index]._resourceId);
+ _items.remove_at(index);
+ --index;
+ }
+}
+
+int SoundMan::find(int resourceId) {
+ for (int index = 0; index < (int)_items.size(); ++index)
+ if (_items[index]._resourceId == resourceId)
+ return index;
+ return -1;
+}
+
+} // End of namespace Gnap
diff --git a/engines/gnap/sound.h b/engines/gnap/sound.h
new file mode 100644
index 0000000000..de3981245d
--- /dev/null
+++ b/engines/gnap/sound.h
@@ -0,0 +1,57 @@
+/* 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.
+ *
+ */
+
+#ifndef GNAP_SOUND_H
+#define GNAP_SOUND_H
+
+#include "gnap/gnap.h"
+#include "gnap/resource.h"
+#include "audio/mixer.h"
+#include "common/array.h"
+
+namespace Gnap {
+
+struct SoundItem {
+ int _resourceId;
+ Audio::SoundHandle _handle;
+};
+
+class SoundMan {
+public:
+ SoundMan(GnapEngine *vm);
+ ~SoundMan();
+ void playSound(int resourceId, bool looping);
+ void stopSound(int resourceId);
+ void setSoundVolume(int resourceId, int volume);
+ bool isSoundPlaying(int resourceId);
+ void stopAll();
+ void update();
+protected:
+ GnapEngine *_vm;
+ Common::Array<SoundItem> _items;
+
+ int find(int resourceId);
+};
+
+} // End of namespace Gnap
+
+#endif // GNAP_SOUND_H
diff --git a/engines/gob/detection/detection.cpp b/engines/gob/detection/detection.cpp
index 3b26f63c39..b0aa78f416 100644
--- a/engines/gob/detection/detection.cpp
+++ b/engines/gob/detection/detection.cpp
@@ -33,7 +33,7 @@ class GobMetaEngine : public AdvancedMetaEngine {
public:
GobMetaEngine();
- virtual GameDescriptor findGame(const char *gameid) const;
+ virtual GameDescriptor findGame(const char *gameId) const;
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const;
@@ -55,12 +55,12 @@ private:
GobMetaEngine::GobMetaEngine() :
AdvancedMetaEngine(Gob::gameDescriptions, sizeof(Gob::GOBGameDescription), gobGames) {
- _singleid = "gob";
- _guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
+ _singleId = "gob";
+ _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD);
}
-GameDescriptor GobMetaEngine::findGame(const char *gameid) const {
- return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
+GameDescriptor GobMetaEngine::findGame(const char *gameId) const {
+ return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
const ADGameDescription *GobMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
diff --git a/engines/gob/detection/tables_fascin.h b/engines/gob/detection/tables_fascin.h
index 7c7c9a7a2f..92272e9852 100644
--- a/engines/gob/detection/tables_fascin.h
+++ b/engines/gob/detection/tables_fascin.h
@@ -187,6 +187,20 @@
kFeaturesCD,
"intro.stk", 0, 0
},
+{ // From bug #7069
+ {
+ "fascination",
+ "",
+ AD_ENTRY1s("disk0.stk", "fbf73d7919e1a6752d924eccc14838d7", 190498),
+ ES_ESP,
+ kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO2(GUIO_NOSUBTITLES, GUIO_NOSPEECH)
+ },
+ kGameTypeFascination,
+ kFeaturesNone,
+ "disk0.stk", 0, 0
+},
// -- Amiga --
diff --git a/engines/gob/detection/tables_playtoons.h b/engines/gob/detection/tables_playtoons.h
index f249e3ffa6..e495db9e25 100644
--- a/engines/gob/detection/tables_playtoons.h
+++ b/engines/gob/detection/tables_playtoons.h
@@ -222,6 +222,24 @@
kFeatures640x480,
"intro2.stk", 0, 0
},
+{ // Version 1.002. Bug #7052
+ {
+ "playtoons2",
+ "",
+ {
+ {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338},
+ {"spirou.stk", 0, "91080dc148de1bbd6a97321c1a1facf3", 9817086},
+ {0, 0, 0, 0}
+ },
+ FR_FRA,
+ kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO3(GUIO_NOSUBTITLES, GUIO_NOSPEECH, GUIO_NOASPECT)
+ },
+ kGameTypePlaytoons,
+ kFeatures640x480,
+ "intro2.stk", 0, 0
+},
{
{
"playtoons2",
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp
index 24bdb858d8..dfbff33c63 100644
--- a/engines/gob/gob.cpp
+++ b/engines/gob/gob.cpp
@@ -26,6 +26,7 @@
#include "base/plugins.h"
#include "common/config-manager.h"
#include "audio/mididrv.h"
+#include "audio/mixer.h"
#include "gui/gui-manager.h"
#include "gui/dialog.h"
@@ -296,9 +297,7 @@ Common::Error GobEngine::run() {
if (isCD())
checkCD();
- int cd_num = ConfMan.getInt("cdrom");
- if (cd_num >= 0)
- _system->getAudioCDManager()->openCD(cd_num);
+ _system->getAudioCDManager()->open();
_global->_debugFlag = 1;
_video->_doRangeClamp = true;
@@ -430,6 +429,23 @@ Common::Error GobEngine::initGameParts() {
_map = new Map_v1(this);
_goblin = new Goblin_v1(this);
_scenery = new Scenery_v1(this);
+
+ // WORKAROUND: The EGA version of Gobliiins claims a few resources are
+ // larger than they actually are. The original happily reads
+ // past the resource structure boundary, but we don't.
+ // To make sure we don't throw an error like we normally do
+ // (which leads to these resources not loading), we enable
+ // this workaround that automatically fixes the resources
+ // sizes.
+ //
+ // This glitch is visible in levels
+ // - 03 (ICIGCAA)
+ // - 09 (ICVGCGT)
+ // - 16 (TCVQRPM)
+ // - 20 (NNGWTTO)
+ // See also ScummVM bug report #7162.
+ if (isEGA())
+ _resourceSizeWorkaround = true;
break;
case kGameTypeGeisha:
diff --git a/engines/gob/inter_playtoons.cpp b/engines/gob/inter_playtoons.cpp
index 45f573efcd..13d24dc05d 100644
--- a/engines/gob/inter_playtoons.cpp
+++ b/engines/gob/inter_playtoons.cpp
@@ -41,7 +41,6 @@
#include "gob/video.h"
#include "gob/videoplayer.h"
#include "gob/save/saveload.h"
-#include "gob/sound/sound.h"
namespace Gob {
diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp
index 3aa7ad1664..4b58819c01 100644
--- a/engines/gob/inter_v2.cpp
+++ b/engines/gob/inter_v2.cpp
@@ -26,9 +26,6 @@
#include "gui/message.h"
-#include "audio/mixer.h"
-#include "audio/mods/infogrames.h"
-
#include "gob/gob.h"
#include "gob/inter.h"
#include "gob/global.h"
diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp
index 656ca6f5c3..d379d5ab11 100644
--- a/engines/gob/inter_v4.cpp
+++ b/engines/gob/inter_v4.cpp
@@ -205,7 +205,7 @@ void Inter_v4::o4_playVmdOrMusic() {
return;
} else if (props.lastFrame == -9) {
_vm->_sound->bgStop();
- _vm->_sound->bgSetPlayMode(BackgroundAtmosphere::kPlayModeRandom);
+ _vm->_sound->bgSetPlayMode(Sound::kPlayModeRandom);
_vm->_sound->bgPlay(file.c_str(), "SND", SOUND_SND, props.palStart);
return;
} else if (props.lastFrame < 0) {
diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp
index a6e4da75e7..50910e77bd 100644
--- a/engines/gob/pregob/onceupon/onceupon.cpp
+++ b/engines/gob/pregob/onceupon/onceupon.cpp
@@ -30,8 +30,6 @@
#include "gob/anifile.h"
#include "gob/aniobject.h"
-#include "gob/sound/sound.h"
-
#include "gob/pregob/txtfile.h"
#include "gob/pregob/gctfile.h"
diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h
index 021cf2b3d6..108771a63a 100644
--- a/engines/gob/pregob/pregob.h
+++ b/engines/gob/pregob/pregob.h
@@ -29,14 +29,14 @@
#include "gob/util.h"
#include "gob/aniobject.h"
-#include "gob/sound/sounddesc.h"
-
#include "gob/pregob/txtfile.h"
namespace Gob {
class GobEngine;
+class ANIFile;
class Surface;
+class SoundDesc;
class GCTFile;
diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h
index d60458295c..9d6b3053b6 100644
--- a/engines/gob/sound/adlib.h
+++ b/engines/gob/sound/adlib.h
@@ -25,7 +25,6 @@
#include "common/mutex.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
namespace OPL {
diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp
index 21fb70278a..c7be1be96a 100644
--- a/engines/gob/sound/bgatmosphere.cpp
+++ b/engines/gob/sound/bgatmosphere.cpp
@@ -23,6 +23,7 @@
#include "common/array.h"
#include "gob/sound/bgatmosphere.h"
+#include "gob/sound/sound.h"
#include "gob/sound/sounddesc.h"
namespace Gob {
@@ -30,7 +31,7 @@ namespace Gob {
BackgroundAtmosphere::BackgroundAtmosphere(Audio::Mixer &mixer) :
SoundMixer(mixer, Audio::Mixer::kMusicSoundType), _rnd("gobBA") {
- _playMode = kPlayModeLinear;
+ _playMode = Sound::kPlayModeLinear;
_queuePos = -1;
_shaded = false;
_shadable = true;
@@ -56,7 +57,7 @@ void BackgroundAtmosphere::stopBA() {
SoundMixer::stop(0);
}
-void BackgroundAtmosphere::setPlayMode(PlayMode mode) {
+void BackgroundAtmosphere::setPlayMode(Sound::BackgroundPlayMode mode) {
_playMode = mode;
}
@@ -100,11 +101,11 @@ void BackgroundAtmosphere::getNextQueuePos() {
switch (_playMode) {
- case kPlayModeLinear:
+ case Sound::kPlayModeLinear:
_queuePos = (_queuePos + 1) % _queue.size();
break;
- case kPlayModeRandom:
+ case Sound::kPlayModeRandom:
_queuePos = _rnd.getRandomNumber(_queue.size() - 1);
break;
diff --git a/engines/gob/sound/bgatmosphere.h b/engines/gob/sound/bgatmosphere.h
index 1cfc63c79a..138b65a1c1 100644
--- a/engines/gob/sound/bgatmosphere.h
+++ b/engines/gob/sound/bgatmosphere.h
@@ -23,31 +23,30 @@
#ifndef GOB_SOUND_BGATMOSPHERE_H
#define GOB_SOUND_BGATMOSPHERE_H
-#include "audio/mixer.h"
#include "common/array.h"
#include "common/mutex.h"
#include "common/random.h"
+#include "gob/sound/sound.h"
#include "gob/sound/soundmixer.h"
+namespace Audio {
+class Mixer;
+}
+
namespace Gob {
class SoundDesc;
class BackgroundAtmosphere : private SoundMixer {
public:
- enum PlayMode {
- kPlayModeLinear,
- kPlayModeRandom
- };
-
BackgroundAtmosphere(Audio::Mixer &mixer);
~BackgroundAtmosphere();
void playBA();
void stopBA();
- void setPlayMode(PlayMode mode);
+ void setPlayMode(Sound::BackgroundPlayMode mode);
void queueSample(SoundDesc &sndDesc);
void queueClear();
@@ -57,7 +56,7 @@ public:
void unshade();
private:
- PlayMode _playMode;
+ Sound::BackgroundPlayMode _playMode;
Common::Array<SoundDesc *> _queue;
int _queuePos;
diff --git a/engines/gob/sound/pcspeaker.cpp b/engines/gob/sound/pcspeaker.cpp
index d0dcb9a871..7ba9fa75df 100644
--- a/engines/gob/sound/pcspeaker.cpp
+++ b/engines/gob/sound/pcspeaker.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "audio/softsynth/pcspk.h"
#include "gob/sound/pcspeaker.h"
namespace Gob {
diff --git a/engines/gob/sound/pcspeaker.h b/engines/gob/sound/pcspeaker.h
index ba2e00ce3e..2c3a12a168 100644
--- a/engines/gob/sound/pcspeaker.h
+++ b/engines/gob/sound/pcspeaker.h
@@ -24,7 +24,10 @@
#define GOB_SOUND_PCSPEAKER_H
#include "audio/mixer.h"
-#include "audio/softsynth/pcspk.h"
+
+namespace Audio {
+class PCSpeaker;
+}
namespace Gob {
diff --git a/engines/gob/sound/protracker.cpp b/engines/gob/sound/protracker.cpp
index ce29100b85..7cf8dbb37c 100644
--- a/engines/gob/sound/protracker.cpp
+++ b/engines/gob/sound/protracker.cpp
@@ -22,6 +22,7 @@
#include "common/file.h"
+#include "audio/audiostream.h"
#include "audio/mods/protracker.h"
#include "gob/sound/protracker.h"
diff --git a/engines/gob/sound/protracker.h b/engines/gob/sound/protracker.h
index ccd0d51552..17d909346e 100644
--- a/engines/gob/sound/protracker.h
+++ b/engines/gob/sound/protracker.h
@@ -24,7 +24,10 @@
#define GOB_SOUND_PROTRACKER_H
#include "audio/mixer.h"
-#include "audio/audiostream.h"
+
+namespace Audio {
+class AudioStream;
+}
namespace Gob {
diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp
index 22dfe9d3c3..000eafa031 100644
--- a/engines/gob/sound/sound.cpp
+++ b/engines/gob/sound/sound.cpp
@@ -28,6 +28,7 @@
#include "gob/game.h"
#include "gob/inter.h"
+#include "gob/sound/bgatmosphere.h"
#include "gob/sound/pcspeaker.h"
#include "gob/sound/soundblaster.h"
#include "gob/sound/adlplayer.h"
@@ -717,7 +718,7 @@ void Sound::bgStop() {
_bgatmos->queueClear();
}
-void Sound::bgSetPlayMode(BackgroundAtmosphere::PlayMode mode) {
+void Sound::bgSetPlayMode(Sound::BackgroundPlayMode mode) {
if (!_bgatmos)
return;
diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h
index 6ebc323b18..f1fd46d24b 100644
--- a/engines/gob/sound/sound.h
+++ b/engines/gob/sound/sound.h
@@ -23,12 +23,13 @@
#ifndef GOB_SOUND_SOUND_H
#define GOB_SOUND_SOUND_H
+#include "common/str.h"
#include "gob/sound/sounddesc.h"
-#include "gob/sound/bgatmosphere.h"
namespace Gob {
class GobEngine;
+class BackgroundAtmosphere;
class PCSpeaker;
class SoundBlaster;
class ADLPlayer;
@@ -39,6 +40,11 @@ class CDROM;
class Sound {
public:
+ enum BackgroundPlayMode {
+ kPlayModeLinear,
+ kPlayModeRandom
+ };
+
static const int kSoundsCount = 60;
Sound(GobEngine *vm);
@@ -135,7 +141,7 @@ public:
void bgPlay(const char *base, const char *ext, SoundType type, int count);
void bgStop();
- void bgSetPlayMode(BackgroundAtmosphere::PlayMode mode);
+ void bgSetPlayMode(BackgroundPlayMode mode);
void bgShade();
void bgUnshade();
diff --git a/engines/gob/sound/soundblaster.h b/engines/gob/sound/soundblaster.h
index 6a732dbec9..8abed62019 100644
--- a/engines/gob/sound/soundblaster.h
+++ b/engines/gob/sound/soundblaster.h
@@ -24,10 +24,13 @@
#define GOB_SOUND_SOUNDBLASTER_H
#include "common/mutex.h"
-#include "audio/mixer.h"
#include "gob/sound/soundmixer.h"
+namespace Audio {
+class Mixer;
+}
+
namespace Gob {
class SoundDesc;
diff --git a/engines/gob/sound/sounddesc.cpp b/engines/gob/sound/sounddesc.cpp
index f981d0b385..d56387078a 100644
--- a/engines/gob/sound/sounddesc.cpp
+++ b/engines/gob/sound/sounddesc.cpp
@@ -24,7 +24,6 @@
#include "common/memstream.h"
#include "common/textconsole.h"
-#include "audio/mixer.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp
index e97848d27e..bbf4ef4162 100644
--- a/engines/gob/videoplayer.cpp
+++ b/engines/gob/videoplayer.cpp
@@ -21,6 +21,8 @@
*/
+#include "video/coktel_decoder.h"
+
#include "gob/videoplayer.h"
#include "gob/global.h"
#include "gob/dataio.h"
diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h
index 02ed510ec5..1c39ecf2fa 100644
--- a/engines/gob/videoplayer.h
+++ b/engines/gob/videoplayer.h
@@ -29,11 +29,14 @@
#include "common/str.h"
#include "graphics/surface.h"
-#include "video/coktel_decoder.h"
#include "gob/util.h"
#include "gob/draw.h"
+namespace Video {
+class CoktelDecoder;
+}
+
namespace Gob {
class GobEngine;
diff --git a/engines/groovie/cell.cpp b/engines/groovie/cell.cpp
index 24fac17e44..5fceb8f74e 100644
--- a/engines/groovie/cell.cpp
+++ b/engines/groovie/cell.cpp
@@ -30,6 +30,7 @@ CellGame::CellGame() {
_stack_index = _boardStackPtr = 0;
_flag4 = false;
_flag2 = false;
+ _flag1 = false;
_coeff3 = 0;
_moveCount = 0;
diff --git a/engines/groovie/configure.engine b/engines/groovie/configure.engine
index 212a49bec8..f283731a58 100644
--- a/engines/groovie/configure.engine
+++ b/engines/groovie/configure.engine
@@ -1,4 +1,4 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine groovie "Groovie" yes "groovie2" "7th Guest"
+add_engine groovie "Groovie" yes "groovie2" "7th Guest" "highres"
add_engine groovie2 "Groovie 2 games" no "" "" "jpeg 16bit"
diff --git a/engines/groovie/cursor.cpp b/engines/groovie/cursor.cpp
index 442f0bfada..d56698095f 100644
--- a/engines/groovie/cursor.cpp
+++ b/engines/groovie/cursor.cpp
@@ -35,7 +35,7 @@ namespace Groovie {
// Cursor Manager
GrvCursorMan::GrvCursorMan(OSystem *system) :
- _syst(system), _lastTime(0), _current(255), _cursor(NULL) {
+ _syst(system), _lastTime(0), _current(255), _cursor(NULL), _lastFrame(0) {
}
GrvCursorMan::~GrvCursorMan() {
diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp
index a249b66858..b12e264a57 100644
--- a/engines/groovie/detection.cpp
+++ b/engines/groovie/detection.cpp
@@ -322,7 +322,7 @@ static const ADExtraGuiOptionsMap optionsList[] = {
class GroovieMetaEngine : public AdvancedMetaEngine {
public:
GroovieMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(GroovieGameDescription), groovieGames, optionsList) {
- _singleid = "groovie";
+ _singleId = "groovie";
// Use kADFlagUseExtraAsHint in order to distinguish the 11th hour from
// its "Making of" as well as the Clandestiny Trailer; they all share
@@ -333,7 +333,7 @@ public:
// to the detection entries. In the latter case, this TODO should be
// replaced with an according explanation.
_flags = kADFlagUseExtraAsHint;
- _guioptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT);
+ _guiOptions = GUIO3(GUIO_NOSUBTITLES, GUIO_NOSFX, GUIO_NOASPECT);
// Need MIDI directory to detect 11H Mac Installed
_maxScanDepth = 2;
diff --git a/engines/groovie/font.h b/engines/groovie/font.h
index 23e060faf3..5c479b6919 100644
--- a/engines/groovie/font.h
+++ b/engines/groovie/font.h
@@ -44,7 +44,7 @@ private:
int _maxHeight, _maxWidth;
struct Glyph {
- Glyph() : pixels(0) {}
+ Glyph() : pixels(0), width(0), height(0), julia(0) {}
~Glyph() { delete[] pixels; }
byte width;
diff --git a/engines/groovie/graphics.cpp b/engines/groovie/graphics.cpp
index e0c198f377..45956416cd 100644
--- a/engines/groovie/graphics.cpp
+++ b/engines/groovie/graphics.cpp
@@ -31,7 +31,7 @@
namespace Groovie {
GraphicsMan::GraphicsMan(GroovieEngine *vm) :
- _vm(vm), _changed(false), _fading(0) {
+ _vm(vm), _changed(false), _fading(0), _fadeStartTime(0) {
// Create the game surfaces
_foreground.create(640, 320, _vm->_pixelFormat);
_background.create(640, 320, _vm->_pixelFormat);
diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp
index 2021cef6e8..ac77ec3099 100644
--- a/engines/groovie/groovie.cpp
+++ b/engines/groovie/groovie.cpp
@@ -20,9 +20,6 @@
*
*/
-#include "audio/mididrv.h"
-#include "audio/mixer.h"
-
#include "groovie/groovie.h"
#include "groovie/cursor.h"
#include "groovie/detection.h"
@@ -257,11 +254,7 @@ Common::Error GroovieEngine::run() {
// the same cd
if (getPlatform() != Common::kPlatformIOS) {
checkCD();
-
- // Initialize the CD
- int cd_num = ConfMan.getInt("cdrom");
- if (cd_num >= 0)
- _system->getAudioCDManager()->openCD(cd_num);
+ _system->getAudioCDManager()->open();
}
while (!shouldQuit()) {
diff --git a/engines/groovie/groovie.h b/engines/groovie/groovie.h
index d442d39cb2..c2994d20cc 100644
--- a/engines/groovie/groovie.h
+++ b/engines/groovie/groovie.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef GROOVIE_H
-#define GROOVIE_H
+#ifndef GROOVIE_GROOVIE_H
+#define GROOVIE_GROOVIE_H
#include "groovie/debug.h"
#include "groovie/font.h"
@@ -132,4 +132,4 @@ private:
} // End of namespace Groovie
-#endif // GROOVIE_H
+#endif // GROOVIE_GROOVIE_H
diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp
index cf65e012c8..9244dd7c31 100644
--- a/engines/groovie/music.cpp
+++ b/engines/groovie/music.cpp
@@ -44,7 +44,8 @@ namespace Groovie {
MusicPlayer::MusicPlayer(GroovieEngine *vm) :
_vm(vm), _isPlaying(false), _backgroundFileRef(0), _gameVolume(100),
- _prevCDtrack(0), _backgroundDelay(0) {
+ _prevCDtrack(0), _backgroundDelay(0), _fadingStartTime(0), _fadingStartVolume(0),
+ _fadingEndVolume(0), _fadingDuration(0), _userVolume(0) {
}
MusicPlayer::~MusicPlayer() {
@@ -391,6 +392,8 @@ MusicPlayerXMI::MusicPlayerXMI(GroovieEngine *vm, const Common::String &gtlName)
bool milesAudioEnabled = true;
MidiParser::XMidiNewTimbreListProc newTimbreListProc = NULL;
+ _musicType = 0;
+
if (milesAudioEnabled) {
// 7th Guest uses FAT.AD/FAT.OPL/FAT.MT
// 11th Hour uses SAMPLE.AD/SAMPLE.OPL/SAMPLE.MT
diff --git a/engines/groovie/music.h b/engines/groovie/music.h
index dcb91d42a8..8b46cddc1f 100644
--- a/engines/groovie/music.h
+++ b/engines/groovie/music.h
@@ -25,6 +25,8 @@
#include "common/array.h"
#include "common/mutex.h"
+#include "audio/mididrv.h"
+#include "audio/mixer.h"
class MidiParser;
@@ -139,7 +141,7 @@ private:
// Timbres
class Timbre {
public:
- Timbre() : data(NULL) {}
+ Timbre() : data(NULL), patch(0), bank(0), size(0) {}
byte patch;
byte bank;
uint32 size;
diff --git a/engines/groovie/player.cpp b/engines/groovie/player.cpp
index c1b90fbd2c..bbc8918902 100644
--- a/engines/groovie/player.cpp
+++ b/engines/groovie/player.cpp
@@ -21,6 +21,7 @@
*/
#include "common/debug.h"
+#include "audio/audiostream.h"
#include "groovie/player.h"
#include "groovie/groovie.h"
@@ -28,7 +29,8 @@
namespace Groovie {
VideoPlayer::VideoPlayer(GroovieEngine *vm) :
- _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL), _fps(0), _overrideSpeed(false) {
+ _vm(vm), _syst(vm->_system), _file(NULL), _audioStream(NULL), _fps(0), _overrideSpeed(false), _flags(0),
+ _begunPlaying(false), _millisBetweenFrames(0), _lastFrameTime(0) {
}
bool VideoPlayer::load(Common::SeekableReadStream *file, uint16 flags) {
diff --git a/engines/groovie/player.h b/engines/groovie/player.h
index b1aac963f2..952d3ac208 100644
--- a/engines/groovie/player.h
+++ b/engines/groovie/player.h
@@ -24,7 +24,10 @@
#define GROOVIE_PLAYER_H
#include "common/system.h"
-#include "audio/audiostream.h"
+
+namespace Audio {
+class QueuingAudioStream;
+}
namespace Groovie {
diff --git a/engines/groovie/roq.cpp b/engines/groovie/roq.cpp
index f14cacd6b8..c1b6c44c4d 100644
--- a/engines/groovie/roq.cpp
+++ b/engines/groovie/roq.cpp
@@ -40,6 +40,7 @@
// Required for the YUV to RGB conversion
#include "graphics/conversion.h"
#endif
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp
index eef97b6ff9..47fdaacf7a 100644
--- a/engines/groovie/script.cpp
+++ b/engines/groovie/script.cpp
@@ -21,7 +21,6 @@
*/
#include "audio/mididrv.h"
-#include "audio/mixer.h"
#include "groovie/script.h"
#include "groovie/cell.h"
diff --git a/engines/groovie/vdx.cpp b/engines/groovie/vdx.cpp
index 09c2e0d3ea..94b6aa0680 100644
--- a/engines/groovie/vdx.cpp
+++ b/engines/groovie/vdx.cpp
@@ -28,6 +28,7 @@
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/textconsole.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
#include "graphics/palette.h"
diff --git a/engines/hopkins/configure.engine b/engines/hopkins/configure.engine
index c38ecd4cd2..cd9f50a5f9 100644
--- a/engines/hopkins/configure.engine
+++ b/engines/hopkins/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine hopkins "Hopkins FBI" yes "" "" "16bit"
+add_engine hopkins "Hopkins FBI" yes "" "" "16bit highres"
diff --git a/engines/hopkins/detection.cpp b/engines/hopkins/detection.cpp
index cc1e84f5f8..cfdbf8030c 100644
--- a/engines/hopkins/detection.cpp
+++ b/engines/hopkins/detection.cpp
@@ -111,7 +111,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Hopkins FBI (c)1997-2003 MP Entertainment";
+ return "Hopkins FBI (C)1997-2003 MP Entertainment";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/hopkins/hopkins.h b/engines/hopkins/hopkins.h
index b782d103a8..30140baa2e 100644
--- a/engines/hopkins/hopkins.h
+++ b/engines/hopkins/hopkins.h
@@ -48,7 +48,6 @@
#include "common/util.h"
#include "engines/engine.h"
#include "graphics/surface.h"
-#include "gui/debugger.h"
/**
* This is the namespace of the Hopkins engine.
diff --git a/engines/hopkins/sound.cpp b/engines/hopkins/sound.cpp
index 6660233740..3030636a59 100644
--- a/engines/hopkins/sound.cpp
+++ b/engines/hopkins/sound.cpp
@@ -26,6 +26,8 @@
#include "hopkins/hopkins.h"
#include "audio/decoders/adpcm_intern.h"
+#include "audio/decoders/wave.h"
+#include "audio/softsynth/pcspk.h"
#include "common/system.h"
#include "common/config-manager.h"
#include "common/file.h"
diff --git a/engines/hopkins/sound.h b/engines/hopkins/sound.h
index 1fb4f9ae71..49c5846198 100644
--- a/engines/hopkins/sound.h
+++ b/engines/hopkins/sound.h
@@ -25,10 +25,16 @@
#include "common/scummsys.h"
#include "common/str.h"
-#include "audio/audiostream.h"
-#include "audio/decoders/wave.h"
#include "audio/mixer.h"
+namespace Audio {
+class RewindableAudioStream;
+}
+
+namespace Common {
+class SeekableReadStream;
+}
+
namespace Hopkins {
class VoiceItem {
diff --git a/engines/hugo/detection.cpp b/engines/hugo/detection.cpp
index c48a26b405..4e4746c002 100644
--- a/engines/hugo/detection.cpp
+++ b/engines/hugo/detection.cpp
@@ -41,7 +41,7 @@ uint32 HugoEngine::getFeatures() const {
}
const char *HugoEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
diff --git a/engines/hugo/dialogs.cpp b/engines/hugo/dialogs.cpp
index 8b145b78d8..c741c6a837 100644
--- a/engines/hugo/dialogs.cpp
+++ b/engines/hugo/dialogs.cpp
@@ -26,7 +26,8 @@
#include "image/bmp.h"
#include "hugo/hugo.h"
-#include "hugo/display.h"
+#include "hugo/dialogs.h"
+#include "hugo/file.h"
#include "hugo/parser.h"
#include "hugo/schedule.h"
#include "hugo/sound.h"
diff --git a/engines/hugo/dialogs.h b/engines/hugo/dialogs.h
index 55bb8f9fd0..aebbeee8c1 100644
--- a/engines/hugo/dialogs.h
+++ b/engines/hugo/dialogs.h
@@ -28,6 +28,8 @@
namespace Hugo {
+class HugoEngine;
+
enum MenuOption {
kMenuWhat = 0,
kMenuMusic,
diff --git a/engines/hugo/display.cpp b/engines/hugo/display.cpp
index a8a22fb4b9..17627608bd 100644
--- a/engines/hugo/display.cpp
+++ b/engines/hugo/display.cpp
@@ -37,6 +37,7 @@
#include "hugo/hugo.h"
#include "hugo/display.h"
+#include "hugo/file.h"
#include "hugo/inventory.h"
#include "hugo/util.h"
#include "hugo/object.h"
diff --git a/engines/hugo/display.h b/engines/hugo/display.h
index e152a7f868..99fda0a638 100644
--- a/engines/hugo/display.h
+++ b/engines/hugo/display.h
@@ -30,6 +30,11 @@
#ifndef HUGO_DISPLAY_H
#define HUGO_DISPLAY_H
+namespace Common {
+class ReadStream;
+class WriteStream;
+}
+
namespace Hugo {
enum OverlayState {kOvlUndef, kOvlForeground, kOvlBackground}; // Overlay state
diff --git a/engines/hugo/file.h b/engines/hugo/file.h
index d43528f0f8..731eb70a35 100644
--- a/engines/hugo/file.h
+++ b/engines/hugo/file.h
@@ -30,6 +30,8 @@
#ifndef HUGO_FILE_H
#define HUGO_FILE_H
+#include "common/file.h"
+
namespace Hugo {
/**
* Enumerate overlay file types
diff --git a/engines/hugo/hugo.cpp b/engines/hugo/hugo.cpp
index 8f89832f6b..267eb08436 100644
--- a/engines/hugo/hugo.cpp
+++ b/engines/hugo/hugo.cpp
@@ -29,7 +29,10 @@
#include "common/textconsole.h"
#include "hugo/hugo.h"
+#include "hugo/console.h"
+#include "hugo/dialogs.h"
#include "hugo/file.h"
+#include "hugo/game.h"
#include "hugo/schedule.h"
#include "hugo/display.h"
#include "hugo/mouse.h"
diff --git a/engines/hugo/hugo.h b/engines/hugo/hugo.h
index cc0fcc6ec2..85209afe06 100644
--- a/engines/hugo/hugo.h
+++ b/engines/hugo/hugo.h
@@ -20,23 +20,20 @@
*
*/
-#ifndef HUGO_H
-#define HUGO_H
+#ifndef HUGO_HUGO_H
+#define HUGO_HUGO_H
#include "engines/engine.h"
-#include "common/file.h"
-#include "hugo/console.h"
-#include "hugo/dialogs.h"
// This include is here temporarily while the engine is being refactored.
#include "hugo/game.h"
-#include "hugo/file.h"
#define HUGO_DAT_VER_MAJ 0 // 1 byte
#define HUGO_DAT_VER_MIN 42 // 1 byte
#define DATAALIGNMENT 4
namespace Common {
+class SeekableReadStream;
class RandomSource;
}
@@ -209,6 +206,8 @@ class SoundHandler;
class IntroHandler;
class ObjectHandler;
class TextHandler;
+class TopMenu;
+class HugoConsole;
class HugoEngine : public Engine {
public:
@@ -342,4 +341,4 @@ private:
} // End of namespace Hugo
-#endif // Hugo_H
+#endif // HUGO_HUGO_H
diff --git a/engines/hugo/intro.cpp b/engines/hugo/intro.cpp
index 26ef65edf8..e15291e03b 100644
--- a/engines/hugo/intro.cpp
+++ b/engines/hugo/intro.cpp
@@ -29,9 +29,13 @@
#include "common/system.h"
#include "common/textconsole.h"
+#include "graphics/font.h"
+#include "graphics/pixelformat.h"
#include "hugo/hugo.h"
#include "hugo/intro.h"
+#include "hugo/file.h"
+#include "hugo/game.h"
#include "hugo/util.h"
#include "hugo/display.h"
#include "hugo/sound.h"
diff --git a/engines/hugo/intro.h b/engines/hugo/intro.h
index 7af53c8922..d40cffbfaf 100644
--- a/engines/hugo/intro.h
+++ b/engines/hugo/intro.h
@@ -29,6 +29,7 @@
#ifndef INTRO_H
#define INTRO_H
+#include "graphics/surface.h"
#include "graphics/fonts/winfont.h"
namespace Hugo {
diff --git a/engines/hugo/mouse.cpp b/engines/hugo/mouse.cpp
index 3674c90757..8c0ba12f8f 100644
--- a/engines/hugo/mouse.cpp
+++ b/engines/hugo/mouse.cpp
@@ -33,6 +33,7 @@
#include "common/system.h"
#include "hugo/hugo.h"
+#include "hugo/dialogs.h"
#include "hugo/game.h"
#include "hugo/mouse.h"
#include "hugo/schedule.h"
diff --git a/engines/hugo/mouse.h b/engines/hugo/mouse.h
index f9d547ec86..0bfa1b0db4 100644
--- a/engines/hugo/mouse.h
+++ b/engines/hugo/mouse.h
@@ -29,6 +29,13 @@
#ifndef HUGO_MOUSE_H
#define HUGO_MOUSE_H
+
+#include "hugo/game.h"
+
+namespace Common {
+class ReadStream;
+}
+
namespace Hugo {
class MouseHandler {
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index 998dd5df58..7ee0198882 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -29,12 +29,12 @@
#include "common/events.h"
#include "common/textconsole.h"
+#include "gui/debugger.h"
#include "hugo/hugo.h"
#include "hugo/display.h"
#include "hugo/parser.h"
#include "hugo/file.h"
-#include "hugo/schedule.h"
#include "hugo/util.h"
#include "hugo/route.h"
#include "hugo/sound.h"
diff --git a/engines/hugo/parser.h b/engines/hugo/parser.h
index 5a2ac7d375..dfdd984832 100644
--- a/engines/hugo/parser.h
+++ b/engines/hugo/parser.h
@@ -32,6 +32,7 @@
namespace Common {
struct Event;
+class ReadStream;
}
namespace Hugo {
diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp
index 8591709dc3..09de256789 100644
--- a/engines/hugo/sound.cpp
+++ b/engines/hugo/sound.cpp
@@ -37,6 +37,7 @@
#include "audio/decoders/raw.h"
#include "audio/audiostream.h"
#include "audio/midiparser.h"
+#include "audio/softsynth/pcspk.h"
#include "hugo/hugo.h"
#include "hugo/game.h"
diff --git a/engines/hugo/sound.h b/engines/hugo/sound.h
index 6c3420918d..a623569a8b 100644
--- a/engines/hugo/sound.h
+++ b/engines/hugo/sound.h
@@ -32,7 +32,10 @@
#include "audio/mixer.h"
#include "audio/midiplayer.h"
-#include "audio/softsynth/pcspk.h"
+
+namespace Audio {
+class PCSpeaker;
+}
namespace Hugo {
diff --git a/engines/hugo/text.cpp b/engines/hugo/text.cpp
index 50b2b64260..617fccc36d 100644
--- a/engines/hugo/text.cpp
+++ b/engines/hugo/text.cpp
@@ -20,6 +20,7 @@
*
*/
#include "common/system.h"
+#include "common/stream.h"
#include "hugo/hugo.h"
#include "hugo/text.h"
diff --git a/engines/hugo/util.cpp b/engines/hugo/util.cpp
index 7b75bf2bc5..bc1525382c 100644
--- a/engines/hugo/util.cpp
+++ b/engines/hugo/util.cpp
@@ -28,13 +28,11 @@
*/
#include "common/system.h"
+#include "common/util.h"
#include "gui/message.h"
-#include "hugo/game.h"
-#include "hugo/hugo.h"
+#include "hugo/dialogs.h"
#include "hugo/util.h"
-#include "hugo/sound.h"
-#include "hugo/text.h"
namespace Hugo {
diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp
index 6683f973ca..614d23f70e 100644
--- a/engines/kyra/debugger.cpp
+++ b/engines/kyra/debugger.cpp
@@ -31,8 +31,6 @@
#include "common/system.h"
#include "common/config-manager.h"
-#include "gui/message.h"
-
namespace Kyra {
Debugger::Debugger(KyraEngine_v1 *vm)
diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp
index 38a5ab8440..2264d99dde 100644
--- a/engines/kyra/eobcommon.cpp
+++ b/engines/kyra/eobcommon.cpp
@@ -24,7 +24,8 @@
#include "kyra/kyra_rpg.h"
#include "kyra/resource.h"
-#include "kyra/sound_intern.h"
+#include "engines/kyra/sound.h"
+#include "engines/kyra/sound_adlib.h"
#include "kyra/script_eob.h"
#include "kyra/timer.h"
#include "kyra/debugger.h"
@@ -32,9 +33,6 @@
#include "common/config-manager.h"
#include "common/translation.h"
-#include "audio/mididrv.h"
-#include "audio/mixer.h"
-
#include "backends/keymapper/keymapper.h"
namespace Kyra {
diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp
index 55a23b2a1a..3a2e631744 100644
--- a/engines/kyra/items_lok.cpp
+++ b/engines/kyra/items_lok.cpp
@@ -844,8 +844,6 @@ void KyraEngine_LoK::updatePlayerItemsForScene() {
uint8 item = _currentCharacter->inventoryItems[i];
if (item >= 29 && item < 33) {
++item;
- if (item > 33)
- item = 33;
_currentCharacter->inventoryItems[i] = item;
redraw = true;
}
diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp
index 80511c674d..118ca8dfaa 100644
--- a/engines/kyra/kyra_lok.cpp
+++ b/engines/kyra/kyra_lok.cpp
@@ -33,8 +33,6 @@
#include "common/config-manager.h"
#include "common/debug-channels.h"
-#include "gui/message.h"
-
namespace Kyra {
KyraEngine_LoK::KyraEngine_LoK(OSystem *system, const GameFlags &flags)
diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp
index 925dcf7bfe..106420d9c2 100644
--- a/engines/kyra/kyra_v2.cpp
+++ b/engines/kyra/kyra_v2.cpp
@@ -46,6 +46,8 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi
memset(&_sceneScriptState, 0, sizeof(_sceneScriptState));
memset(&_sceneScriptData, 0, sizeof(_sceneScriptData));
+ Common::fill(_sceneSpecialScriptsTimer, ARRAYEND(_sceneSpecialScriptsTimer), 0);
+
_animObjects = 0;
_runFlag = true;
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index e060b307af..af58397200 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -463,6 +463,7 @@ private:
const uint8 *_musicTrackMap;
const uint16 *_ingameSoundIndex;
+ int _ingameSoundIndexSize;
const uint8 *_ingameGMSoundIndex;
int _ingameGMSoundIndexSize;
const uint8 *_ingameMT32SoundIndex;
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index 3ab08a4c7c..c3ebf6e5fe 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -203,7 +203,6 @@ enum KyraResources {
k1ConfigStrings,
k1AudioTracks,
- k1AudioTracks2,
k1AudioTracksIntro,
k1CreditsStrings,
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index 1d741d8bd0..1703fb904e 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -44,15 +44,17 @@
#include "common/mutex.h"
#include "common/config-manager.h"
-#include "audio/mixer.h"
#include "audio/fmopl.h"
-#include "audio/audiostream.h"
// Basic AdLib Programming:
// http://www.gamedev.net/reference/articles/article446.asp
#define CALLBACKS_PER_SECOND 72
+namespace Audio {
+class Mixer;
+}
+
namespace Kyra {
class AdLibDriver {
diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index 8be0cb6ab9..6e7551ed0e 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -161,7 +161,7 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
return;
_lastSfxTrack = track;
- if (track == -1 || track >= _ingameSoundListSize)
+ if (track == -1 || track >= _ingameSoundIndexSize)
return;
volume &= 0xFF;
@@ -216,10 +216,10 @@ bool LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
for (int i = 3; i > 0; i--) {
int dir = calcMonsterDirection(cbl & 0x1F, cbl >> 5, block & 0x1F, block >> 5);
cbl = (cbl + blockShiftTable[dir]) & 0x3FF;
- if (cbl != block) {
- if (testWallFlag(cbl, 0, 1))
- _environmentSfxVol >>= 1;
- }
+ if (cbl == block)
+ break;
+ if (testWallFlag(cbl, 0, 1))
+ _environmentSfxVol >>= 1;
}
}
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 65ab4f31ef..646f908b94 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -68,11 +68,14 @@ bool SoundTowns::init() {
_player->driver()->intf()->callback(70, 0x33);*/
_player->driver()->setOutputVolume(1, 118, 118);
+ // Initialize CD for audio
+ g_system->getAudioCDManager()->open();
+
return true;
}
void SoundTowns::process() {
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
}
void SoundTowns::playTrack(uint8 track) {
@@ -95,7 +98,7 @@ void SoundTowns::playTrack(uint8 track) {
if (_musicEnabled == 2 && trackNum != -1) {
_player->driver()->setOutputVolume(1, 118, 118);
g_system->getAudioCDManager()->play(trackNum + 1, loop ? -1 : 1, 0, 0);
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
_cdaPlaying = true;
} else if (_musicEnabled) {
playEuphonyTrack(READ_LE_UINT32(&res()->cdaTable[tTableIndex]), loop);
@@ -108,7 +111,7 @@ void SoundTowns::playTrack(uint8 track) {
void SoundTowns::haltTrack() {
_lastTrack = -1;
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
_cdaPlaying = false;
for (int i = 0; i < 6; i++)
@@ -407,6 +410,10 @@ bool SoundPC98::init() {
_driver = new TownsPC98_AudioDriver(_mixer, TownsPC98_AudioDriver::kType26);
bool reslt = _driver->init();
updateVolumeSettings();
+
+ // Initialize CD for audio
+ g_system->getAudioCDManager()->open();
+
return reslt;
}
@@ -471,7 +478,7 @@ void SoundPC98::playTrack(uint8 track) {
void SoundPC98::haltTrack() {
_lastTrack = -1;
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
_driver->reset();
}
@@ -529,6 +536,10 @@ bool SoundTownsPC98_v2::init() {
if (_resInfo[_currentResourceSet])
if (_resInfo[_currentResourceSet]->cdaTableSize)
_vm->checkCD();
+
+ // Initialize CD for audio
+ bool hasRealCD = g_system->getAudioCDManager()->open();
+
// FIXME: While checking for 'track1.XXX(X)' looks like
// a good idea, we should definitely not be doing this
// here. Basically our filenaming scheme could change
@@ -538,7 +549,7 @@ bool SoundTownsPC98_v2::init() {
// check if we have access to CD audio.
Resource *r = _vm->resource();
if (_musicEnabled &&
- (r->exists("track1.mp3") || r->exists("track1.ogg") || r->exists("track1.flac") || r->exists("track1.fla")
+ (hasRealCD || r->exists("track1.mp3") || r->exists("track1.ogg") || r->exists("track1.flac") || r->exists("track1.fla")
|| r->exists("track01.mp3") || r->exists("track01.ogg") || r->exists("track01.flac") || r->exists("track01.fla")))
_musicEnabled = 2;
else
@@ -580,7 +591,7 @@ void SoundTownsPC98_v2::loadSoundFile(Common::String file) {
}
void SoundTownsPC98_v2::process() {
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
}
void SoundTownsPC98_v2::playTrack(uint8 track) {
@@ -610,7 +621,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
if (_musicEnabled == 2 && trackNum != -1) {
g_system->getAudioCDManager()->play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0);
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
} else if (_musicEnabled) {
_driver->cont();
}
@@ -621,7 +632,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
void SoundTownsPC98_v2::haltTrack() {
_lastTrack = -1;
g_system->getAudioCDManager()->stop();
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
_driver->reset();
}
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 1a2e2c093c..e99321ddcb 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -39,7 +39,7 @@
namespace Kyra {
-#define RESFILE_VERSION 87
+#define RESFILE_VERSION 88
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
@@ -805,19 +805,11 @@ void KyraEngine_LoK::initStaticResource() {
}
// audio resource assignment
- int size1, size2;
- const char *const *soundfiles1 = _staticres->loadStrings(k1AudioTracks, size1);
- const char *const *soundfiles2 = _staticres->loadStrings(k1AudioTracks2, size2);
- int soundFilesSize = size1 + size2;
+ int soundFilesSize;
+ const char *const *soundFiles = _staticres->loadStrings(k1AudioTracks, soundFilesSize);
int soundFilesIntroSize = 0;
int cdaTableSize = 0;
- const char **soundFiles = 0;
- if (soundFilesSize) {
- soundFiles = new const char*[soundFilesSize];
- for (int i = 0; i < soundFilesSize; i++)
- soundFiles[i] = (i < size1) ? soundfiles1[i] : soundfiles2[i - size1];
- }
const char *const *soundFilesIntro = _staticres->loadStrings(k1AudioTracksIntro, soundFilesIntroSize);
const int32 *cdaTable = (const int32 *)_staticres->loadRawData(k1TownsCDATable, cdaTableSize);
diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp
index 9a4fc281d5..c40b4a0c7d 100644
--- a/engines/kyra/staticres_lol.cpp
+++ b/engines/kyra/staticres_lol.cpp
@@ -255,7 +255,7 @@ void LoLEngine::initStaticResource() {
int tempSize;
_pakFileList = _staticres->loadStrings(kLoLIngamePakFiles, _pakFileListSize);
_charDefaults = _staticres->loadCharData(kLoLCharacterDefs, _charDefaultsSize);
- _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(kLoLIngameSfxIndex, tempSize);
+ _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(kLoLIngameSfxIndex, _ingameSoundIndexSize);
_musicTrackMap = _staticres->loadRawData(kLoLMusicTrackMap, tempSize);
_ingameGMSoundIndex = _staticres->loadRawData(kLoLIngameGMSfxIndex, _ingameGMSoundIndexSize);
_ingameMT32SoundIndex = _staticres->loadRawData(kLoLIngameMT32SfxIndex, _ingameMT32SoundIndexSize);
diff --git a/engines/lab/anim.cpp b/engines/lab/anim.cpp
index f2e6992375..2dc580735e 100644
--- a/engines/lab/anim.cpp
+++ b/engines/lab/anim.cpp
@@ -28,6 +28,8 @@
*
*/
+#include "common/file.h"
+
#include "lab/lab.h"
#include "lab/anim.h"
@@ -206,6 +208,8 @@ void Anim::diffNextFrame(bool onlyDiffData) {
_vm->updateEvents();
_vm->waitTOF();
}
+
+ _waitForEffect = false;
}
_size -= 8;
@@ -215,7 +219,9 @@ void Anim::diffNextFrame(bool onlyDiffData) {
_diffFile->skip(2);
// Sound effects embedded in animations are started here. These are
- // usually animation-specific, like door opening sounds, and are not looped
+ // usually animation-specific, like door opening sounds, and are not looped.
+ // The engine should wait for all such sounds to end.
+ _waitForEffect = true;
_vm->_music->playSoundEffect(_sampleSpeed, _size, false, _diffFile);
break;
@@ -231,6 +237,8 @@ void Anim::diffNextFrame(bool onlyDiffData) {
if (drawOnScreen)
didTOF = true;
}
+
+ _waitForEffect = false;
}
_isPlaying = false;
diff --git a/engines/lab/detection.cpp b/engines/lab/detection.cpp
index 8d81e5f0ae..30890b5acf 100644
--- a/engines/lab/detection.cpp
+++ b/engines/lab/detection.cpp
@@ -115,7 +115,7 @@ uint32 LabEngine::getFeatures() const {
class LabMetaEngine : public AdvancedMetaEngine {
public:
LabMetaEngine() : AdvancedMetaEngine(labDescriptions, sizeof(ADGameDescription), lab_setting) {
- _singleid = "lab";
+ _singleId = "lab";
_maxScanDepth = 4;
_directoryGlobs = directoryGlobs;
@@ -127,7 +127,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Labyrinth of Time (c) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
+ return "Labyrinth of Time (C) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -197,26 +197,7 @@ int LabMetaEngine::getMaximumSaveSlot() const {
void LabMetaEngine::removeSaveState(const char *target, int slot) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
- Common::String filename = Common::String::format("%s.%03u", target, slot);
-
- saveFileMan->removeSavefile(filename.c_str());
-
- Common::StringArray 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::StringArray::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,
- if (slotNum > slot) {
- saveFileMan->renameSavefile(file->c_str(), filename.c_str());
- filename = Common::String::format("%s.%03u", target, ++slot);
- }
- }
+ saveFileMan->removeSavefile(Common::String::format("%s.%03u", target, slot));
}
SaveStateDescriptor LabMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
diff --git a/engines/lab/dispman.cpp b/engines/lab/dispman.cpp
index af235f234b..d642f2fed5 100644
--- a/engines/lab/dispman.cpp
+++ b/engines/lab/dispman.cpp
@@ -28,6 +28,7 @@
*
*/
+#include "common/file.h"
#include "graphics/palette.h"
#include "lab/lab.h"
diff --git a/engines/lab/engine.cpp b/engines/lab/engine.cpp
index 6ba405380e..4f0a0da777 100644
--- a/engines/lab/engine.cpp
+++ b/engines/lab/engine.cpp
@@ -29,6 +29,7 @@
*/
#include "common/config-manager.h"
+#include "common/file.h"
#include "gui/message.h"
diff --git a/engines/lab/intro.cpp b/engines/lab/intro.cpp
index 01e8cac401..0184ff7c69 100644
--- a/engines/lab/intro.cpp
+++ b/engines/lab/intro.cpp
@@ -28,6 +28,8 @@
*
*/
+#include "common/file.h"
+
#include "lab/lab.h"
#include "lab/anim.h"
diff --git a/engines/lab/lab.cpp b/engines/lab/lab.cpp
index 9b0ebfc4e5..39b2feb93d 100644
--- a/engines/lab/lab.cpp
+++ b/engines/lab/lab.cpp
@@ -31,6 +31,7 @@
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/error.h"
+#include "common/file.h"
#include "engines/util.h"
diff --git a/engines/lab/map.cpp b/engines/lab/map.cpp
index 5c6bb07814..057cac3589 100644
--- a/engines/lab/map.cpp
+++ b/engines/lab/map.cpp
@@ -28,6 +28,8 @@
*
*/
+#include "common/file.h"
+
#include "lab/lab.h"
#include "lab/dispman.h"
diff --git a/engines/lab/music.cpp b/engines/lab/music.cpp
index b58d6dc923..579f450456 100644
--- a/engines/lab/music.cpp
+++ b/engines/lab/music.cpp
@@ -28,6 +28,8 @@
*
*/
+#include "common/file.h"
+#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "lab/lab.h"
diff --git a/engines/lab/music.h b/engines/lab/music.h
index 472fe4fef7..8175e350f1 100644
--- a/engines/lab/music.h
+++ b/engines/lab/music.h
@@ -31,9 +31,11 @@
#ifndef LAB_MUSIC_H
#define LAB_MUSIC_H
-#include "common/file.h"
#include "audio/mixer.h"
-#include "audio/audiostream.h"
+
+namespace Common {
+class File;
+}
namespace Lab {
diff --git a/engines/lab/processroom.cpp b/engines/lab/processroom.cpp
index 44c8d65d7c..68e6e63c1d 100644
--- a/engines/lab/processroom.cpp
+++ b/engines/lab/processroom.cpp
@@ -238,6 +238,8 @@ void LabEngine::doActions(const ActionList &actionList) {
ActionList::const_iterator action;
for (action = actionList.begin(); action != actionList.end(); ++action) {
updateEvents();
+ if (_quitLab || shouldQuit())
+ return;
switch (action->_actionType) {
case kActionPlaySound:
@@ -252,16 +254,9 @@ void LabEngine::doActions(const ActionList &actionList) {
_music->loadSoundEffect(action->_messages[0], true, false);
break;
- case kActionShowDiff: {
- bool curWait = _anim->_waitForEffect;
- // Pause the engine until the sound is finished
- _anim->_waitForEffect = true;
+ case kActionShowDiff:
_graphics->readPict(action->_messages[0], true);
-
- // Restore the previous value of _waitForEffect
- _anim->_waitForEffect = curWait;
break;
- }
case kActionShowDiffLooping: // used in scene 44 (heart of the labyrinth, minotaur)
_graphics->readPict(action->_messages[0], false);
@@ -381,6 +376,8 @@ void LabEngine::doActions(const ActionList &actionList) {
while (_system->getMillis() < targetMillis) {
updateEvents();
+ if (_quitLab || shouldQuit())
+ return;
_anim->diffNextFrame();
}
}
@@ -409,6 +406,8 @@ void LabEngine::doActions(const ActionList &actionList) {
case kActionWaitSound: // used in scene 44 (heart of the labyrinth / ending)
while (_music->isSoundEffectActive()) {
updateEvents();
+ if (_quitLab || shouldQuit())
+ return;
_anim->diffNextFrame();
waitTOF();
}
diff --git a/engines/lab/resource.cpp b/engines/lab/resource.cpp
index aae369fbae..9cb35d1088 100644
--- a/engines/lab/resource.cpp
+++ b/engines/lab/resource.cpp
@@ -28,6 +28,8 @@
*
*/
+#include "common/file.h"
+
#include "lab/lab.h"
#include "lab/dispman.h"
diff --git a/engines/lab/special.cpp b/engines/lab/special.cpp
index 9f9b993afa..7c3cb39931 100644
--- a/engines/lab/special.cpp
+++ b/engines/lab/special.cpp
@@ -28,6 +28,8 @@
*
*/
+#include "common/file.h"
+
#include "lab/lab.h"
#include "lab/anim.h"
diff --git a/engines/lastexpress/configure.engine b/engines/lastexpress/configure.engine
index 807b1a088b..66bac55dea 100644
--- a/engines/lastexpress/configure.engine
+++ b/engines/lastexpress/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine lastexpress "The Last Express" no "" "" "16bit"
+add_engine lastexpress "The Last Express" no "" "" "16bit highres"
diff --git a/engines/lastexpress/detection.cpp b/engines/lastexpress/detection.cpp
index d790582104..52224e4ea5 100644
--- a/engines/lastexpress/detection.cpp
+++ b/engines/lastexpress/detection.cpp
@@ -199,8 +199,8 @@ static const ADGameDescription gameDescriptions[] = {
class LastExpressMetaEngine : public AdvancedMetaEngine {
public:
LastExpressMetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(ADGameDescription), lastExpressGames) {
- _singleid = "lastexpress";
- _guioptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOSFX);
+ _singleId = "lastexpress";
+ _guiOptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOSFX);
}
const char *getName() const {
diff --git a/engines/lastexpress/entities/gendarmes.cpp b/engines/lastexpress/entities/gendarmes.cpp
index b628b8dfe7..1b51dd2006 100644
--- a/engines/lastexpress/entities/gendarmes.cpp
+++ b/engines/lastexpress/entities/gendarmes.cpp
@@ -174,7 +174,7 @@ IMPLEMENT_FUNCTION_IISS(9, Gendarmes, doCompartment, CarIndex, EntityPosition)
strcat((char *)&parameters1->seq1, (char *)&params->seq1);
strcat((char *)&parameters1->seq2, (char *)&params->seq1);
- strcat((char *)&parameters1->seq3, (char *)&params->seq1);
+ Common::strlcat((char *)&parameters1->seq3, (char *)&params->seq1, 9); // Beware, seq3 is smaller than seq1
if ((getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params->param1, (EntityPosition)params->param2)
|| getEntities()->isInsideCompartment(kEntityPlayer, (CarIndex)params->param1, (EntityPosition)parameters2->param7)
diff --git a/engines/lastexpress/lastexpress.h b/engines/lastexpress/lastexpress.h
index b4098f3860..b33784b1e8 100644
--- a/engines/lastexpress/lastexpress.h
+++ b/engines/lastexpress/lastexpress.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef LASTEXPRESS_H
-#define LASTEXPRESS_H
+#ifndef LASTEXPRESS_LASTEXPRESS_H
+#define LASTEXPRESS_LASTEXPRESS_H
#include "lastexpress/debug.h"
#include "lastexpress/eventhandler.h"
@@ -146,4 +146,4 @@ private:
} // End of namespace LastExpress
-#endif // LASTEXPRESS_H
+#endif // LASTEXPRESS_LASTEXPRESS_H
diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp
index 697e6e1269..7308214551 100644
--- a/engines/lastexpress/sound/entry.cpp
+++ b/engines/lastexpress/sound/entry.cpp
@@ -366,7 +366,7 @@ void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) {
assert(_name1.size() <= 16);
assert(_name2.size() <= 16);
- if (_name2.matchString("NISSND?") && (_status.status & kFlagType9) != kFlag3) {
+ if (_name2.matchString("NISSND?") && ((_status.status & kFlagType9) != kFlag3)) {
s.syncAsUint32LE(_status.status);
s.syncAsUint32LE(_type);
s.syncAsUint32LE(_blockCount); // field_8;
diff --git a/engines/lure/detection.cpp b/engines/lure/detection.cpp
index d0a8ee0b4a..690a358bc3 100644
--- a/engines/lure/detection.cpp
+++ b/engines/lure/detection.cpp
@@ -193,12 +193,12 @@ class LureMetaEngine : public AdvancedMetaEngine {
public:
LureMetaEngine() : AdvancedMetaEngine(Lure::gameDescriptions, sizeof(Lure::LureGameDescription), lureGames) {
_md5Bytes = 1024;
- _singleid = "lure";
+ _singleId = "lure";
// Use kADFlagUseExtraAsHint to distinguish between EGA and VGA versions
// of italian Lure when their datafiles sit in the same directory.
_flags = kADFlagUseExtraAsHint;
- _guioptions = GUIO1(GUIO_NOSPEECH);
+ _guiOptions = GUIO1(GUIO_NOSPEECH);
}
virtual const char *getName() const {
diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index 38ca0ba54f..84cc91ec9a 100644
--- a/engines/lure/game.cpp
+++ b/engines/lure/game.cpp
@@ -538,7 +538,7 @@ void Game::handleRightClickMenu() {
hotspot = res.getHotspot(room.hotspotId());
assert(hotspot);
strings.getString(hotspot->nameId, statusLine);
- strcat(statusLine, stringList.getString(S_FOR));
+ Common::strlcat(statusLine, stringList.getString(S_FOR), MAX_DESC_SIZE);
statusLine += strlen(statusLine);
itemId = PopupMenu::ShowItems(GET, player->roomNumber());
@@ -549,7 +549,7 @@ void Game::handleRightClickMenu() {
hotspot = res.getHotspot(room.hotspotId());
assert(hotspot);
strings.getString(hotspot->nameId, statusLine);
- strcat(statusLine, stringList.getString(S_TO));
+ Common::strlcat(statusLine, stringList.getString(S_TO), MAX_DESC_SIZE);
breakFlag = GetTellActions();
break;
@@ -559,7 +559,7 @@ void Game::handleRightClickMenu() {
case DRINK:
hasItems = (res.numInventoryItems() != 0);
if (!hasItems)
- strcat(statusLine, stringList.getString(S_ACTION_NOTHING));
+ Common::strlcat(statusLine, stringList.getString(S_ACTION_NOTHING), MAX_DESC_SIZE);
statusLine += strlen(statusLine);
room.update();
@@ -579,9 +579,9 @@ void Game::handleRightClickMenu() {
assert(useHotspot);
strings.getString(useHotspot->nameId, statusLine);
if (action == GIVE)
- strcat(statusLine, stringList.getString(S_TO));
+ Common::strlcat(statusLine, stringList.getString(S_TO), MAX_DESC_SIZE);
else
- strcat(statusLine, stringList.getString(S_ON));
+ Common::strlcat(statusLine, stringList.getString(S_ON), MAX_DESC_SIZE);
statusLine += strlen(statusLine);
}
else if ((action == DRINK) || (action == EXAMINE))
@@ -762,11 +762,11 @@ bool Game::GetTellActions() {
// Second parameter
action = (Action) commands[_numTellCommands * 3];
if (action == ASK)
- strcat(statusLine, stringList.getString(S_FOR));
+ Common::strlcat(statusLine, stringList.getString(S_FOR), MAX_DESC_SIZE);
else if (action == GIVE)
- strcat(statusLine, stringList.getString(S_TO));
+ Common::strlcat(statusLine, stringList.getString(S_TO), MAX_DESC_SIZE);
else if (action == USE)
- strcat(statusLine, stringList.getString(S_ON));
+ Common::strlcat(statusLine, stringList.getString(S_ON), MAX_DESC_SIZE);
else {
// All other commads don't need a second parameter
++paramIndex;
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp
index fbf93e1e14..29e5d2832e 100644
--- a/engines/lure/hotspots.cpp
+++ b/engines/lure/hotspots.cpp
@@ -1898,8 +1898,8 @@ void Hotspot::doStatus(HotspotData *hotspot) {
endAction();
strings.getString(room.roomNumber(), buffer);
- strcat(buffer, "\n\n");
- strcat(buffer, stringList.getString(S_YOU_ARE_CARRYING));
+ Common::strlcat(buffer, "\n\n", MAX_DESC_SIZE);
+ Common::strlcat(buffer, stringList.getString(S_YOU_ARE_CARRYING), MAX_DESC_SIZE);
// Scan through the list and add in any items assigned to the player
HotspotDataList &list = res.hotspotData();
@@ -1909,25 +1909,25 @@ void Hotspot::doStatus(HotspotData *hotspot) {
if (rec.roomNumber == PLAYER_ID) {
if (numItems++ == 0)
- strcat(buffer, ": ");
+ Common::strlcat(buffer, ": ", MAX_DESC_SIZE);
else
- strcat(buffer, ", ");
+ Common::strlcat(buffer, ", ", MAX_DESC_SIZE);
strings.getString(rec.nameId, buffer + strlen(buffer));
}
}
// If there were no items, add in the word 'nothing'
if (numItems == 0)
- strcat(buffer, stringList.getString(S_INV_NOTHING));
+ Common::strlcat(buffer, stringList.getString(S_INV_NOTHING), MAX_DESC_SIZE);
// If the player has money, add it in
uint16 numGroats = res.fieldList().numGroats();
if (numGroats > 0) {
- strcat(buffer, "\n\n");
- strcat(buffer, stringList.getString(S_YOU_HAVE));
- sprintf(buffer + strlen(buffer), "%d", numGroats);
- strcat(buffer, " ");
- strcat(buffer, stringList.getString((numGroats == 1) ? S_GROAT : S_GROATS));
+ Common::strlcat(buffer, "\n\n", MAX_DESC_SIZE);
+ Common::strlcat(buffer, stringList.getString(S_YOU_HAVE), MAX_DESC_SIZE);
+ snprintf(buffer + strlen(buffer), MAX_DESC_SIZE - strlen(buffer), "%d", numGroats);
+ Common::strlcat(buffer, " ", MAX_DESC_SIZE);
+ Common::strlcat(buffer, stringList.getString((numGroats == 1) ? S_GROAT : S_GROATS), MAX_DESC_SIZE); // Make sure we're not overrunning
}
// Display the dialog
diff --git a/engines/lure/lure.h b/engines/lure/lure.h
index b6eb9123ad..71ce2d3cff 100644
--- a/engines/lure/lure.h
+++ b/engines/lure/lure.h
@@ -20,12 +20,11 @@
*
*/
-#ifndef LURE_H
-#define LURE_H
+#ifndef LURE_LURE_H
+#define LURE_LURE_H
#include "engines/engine.h"
#include "common/rect.h"
-#include "audio/mixer.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/util.h"
diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp
index 3df119a9da..f7dc06033a 100644
--- a/engines/lure/scripts.cpp
+++ b/engines/lure/scripts.cpp
@@ -926,8 +926,8 @@ uint16 Script::execute(uint16 startOffset) {
opcode >>= 1;
if (gDebugLevel >= ERROR_DETAILED)
- strcat(debugInfo, (opcode > S_OPCODE_RANDOM) ? "INVALID" :
- scriptOpcodes[opcode]);
+ Common::strlcat(debugInfo, (opcode > S_OPCODE_RANDOM) ? "INVALID" :
+ scriptOpcodes[opcode], MAX_DESC_SIZE);
if (hasParam) {
// Flag to read next two bytes as active parameter
@@ -1087,7 +1087,7 @@ uint16 Script::execute(uint16 startOffset) {
else if (scriptMethodNames[param] == NULL) strcat(debugInfo, " UNKNOWN METHOD");
else {
strcat(debugInfo, " ");
- strcat(debugInfo, scriptMethodNames[param]);
+ Common::strlcat(debugInfo, scriptMethodNames[param], MAX_DESC_SIZE);
}
// Any params
diff --git a/engines/made/database.cpp b/engines/made/database.cpp
index 3eab31acc2..0020cb398c 100644
--- a/engines/made/database.cpp
+++ b/engines/made/database.cpp
@@ -40,6 +40,7 @@ namespace Made {
*/
Object::Object() : _objData(NULL), _freeData(false) {
+ _objSize = 0;
}
Object::~Object() {
diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp
index 7adc3e1f98..636c2d147c 100644
--- a/engines/made/detection.cpp
+++ b/engines/made/detection.cpp
@@ -521,7 +521,7 @@ static MadeGameDescription g_fallbackDesc = {
class MadeMetaEngine : public AdvancedMetaEngine {
public:
MadeMetaEngine() : AdvancedMetaEngine(Made::gameDescriptions, sizeof(Made::MadeGameDescription), madeGames) {
- _singleid = "made";
+ _singleId = "made";
}
virtual const char *getName() const {
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index ab07ef757b..a29aa2512f 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -58,18 +58,29 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
const GameSettings *g;
+ _eventNum = 0;
+ _eventMouseX = _eventMouseY = 0;
+ _eventKey = 0;
+ _autoStopSound = false;
+ _soundEnergyIndex = 0;
+ _soundEnergyArray = 0;
+ _musicBeatStart = 0;
+ _cdTimeStart = 0;
+
+ _gameId = -1;
+
const char *gameid = ConfMan.get("gameid").c_str();
for (g = madeSettings; g->gameid; ++g)
if (!scumm_stricmp(g->gameid, gameid))
_gameId = g->id;
+ assert(_gameId != -1);
+
_rnd = new Common::RandomSource("made");
_console = new MadeConsole(this);
- int cd_num = ConfMan.getInt("cdrom");
- if (cd_num >= 0)
- _system->getAudioCDManager()->openCD(cd_num);
+ _system->getAudioCDManager()->open();
_pmvPlayer = new PmvPlayer(this, _mixer);
_res = new ResourceReader();
@@ -87,6 +98,8 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
_music = nullptr;
+ _soundRate = 0;
+
// Set default sound frequency
switch (getGameID()) {
case GID_RODNEY:
@@ -270,7 +283,7 @@ void MadeEngine::handleEvents() {
}
}
- _system->getAudioCDManager()->updateCD();
+ _system->getAudioCDManager()->update();
}
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 453e2a4872..0beb132b93 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -223,7 +223,10 @@ bool PmvPlayer::play(const char *filename) {
//delete _audioStream;
delete _fd;
- _surface->free();
+
+ if(_surface)
+ _surface->free();
+
delete _surface;
return !_aborted;
diff --git a/engines/made/redreader.cpp b/engines/made/redreader.cpp
index f92ffd8dd8..a0aaf7be43 100644
--- a/engines/made/redreader.cpp
+++ b/engines/made/redreader.cpp
@@ -102,7 +102,7 @@ int LzhDecompressor::decompress(Common::SeekableReadStream &source, byte *dest,
int bufsize;
byte* buffer;
- buffer = (byte *) malloc(DICSIZ);
+ buffer = (byte *)calloc(DICSIZ, 1);
_source = &source;
_compSize = sourceLen;
diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp
index f8e763e74e..a9734ed47d 100644
--- a/engines/made/resource.cpp
+++ b/engines/made/resource.cpp
@@ -43,6 +43,7 @@ Resource::~Resource() {
PictureResource::PictureResource() : _picture(NULL), _picturePalette(NULL) {
_hasPalette = false;
+ _paletteColorCount = 0;
}
PictureResource::~PictureResource() {
@@ -182,6 +183,9 @@ void PictureResource::loadChunked(byte *source, int size) {
/* AnimationResource */
AnimationResource::AnimationResource() {
+ _flags = 0;
+ _width = 0;
+ _height = 0;
}
AnimationResource::~AnimationResource() {
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index edccb68953..33edb3834c 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -91,6 +91,8 @@ Screen::Screen(MadeEngine *vm) : _vm(vm) {
_currentFontNum = 0;
_fontDrawCtx.clipRect = Common::Rect(320, 200);
_fontDrawCtx.destSurface = _backgroundScreen;
+ _outlineColor = 0;
+ _dropShadowColor = 0;
clearChannels();
}
diff --git a/engines/made/sound.cpp b/engines/made/sound.cpp
index ad49031e7b..62559efa84 100644
--- a/engines/made/sound.cpp
+++ b/engines/made/sound.cpp
@@ -155,6 +155,7 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
};
soundEnergyItem.position = 0;
+ memset(deltaSoundBuffer, 0, 1024);
if (soundEnergyArray)
soundEnergyArray->clear();
@@ -237,6 +238,7 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
break;
default:
+ delete[] soundBuffer;
return;
}
@@ -247,6 +249,9 @@ void decompressSound(byte *source, byte *dest, uint16 chunkSize, uint16 chunkCou
// soundBuffer.
soundBuffer[workChunkSize] = soundBuffer[workChunkSize - 1];
+ for (i = 0; i < chunkSize; i++)
+ soundBuffer[i] = 0;
+
if (deltaType == 1) {
for (i = 0; i < chunkSize - 1; i += 2) {
l = i / 2;
diff --git a/engines/mads/debugger.cpp b/engines/mads/debugger.cpp
index 740c19abad..b9731b1d31 100644
--- a/engines/mads/debugger.cpp
+++ b/engines/mads/debugger.cpp
@@ -158,7 +158,7 @@ bool Debugger::Cmd_ShowCodes(int argc, const char **argv) {
Scene &scene = _vm->_game->_scene;
// Copy the depth/walk surface to the background and flag for screen refresh
- scene._depthSurface.copyTo(&scene._backgroundSurface);
+ scene._depthSurface.blitFrom(scene._backgroundSurface);
scene._spriteSlots.fullRefresh();
// Draw the locations of scene nodes onto the background
diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp
index b3ba60b6d0..4736503a38 100644
--- a/engines/mads/detection.cpp
+++ b/engines/mads/detection.cpp
@@ -149,7 +149,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "MADS (c)";
+ return "MADS (C)";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/mads/dialogs.cpp b/engines/mads/dialogs.cpp
index d9a1e53964..fa656a90c1 100644
--- a/engines/mads/dialogs.cpp
+++ b/engines/mads/dialogs.cpp
@@ -54,21 +54,19 @@ Dialog::~Dialog() {
void Dialog::save() {
_savedSurface = new MSurface(_width, _height);
- _vm->_screen.copyTo(_savedSurface,
+ _savedSurface->blitFrom(*_vm->_screen,
Common::Rect(_position.x, _position.y, _position.x + _width, _position.y + _height),
Common::Point());
- _vm->_screen.copyRectToScreen(getBounds());
+// _vm->_screen->copyRectToScreen(getBounds());
}
void Dialog::restore() {
if (_savedSurface) {
- _savedSurface->copyTo(&_vm->_screen, _position);
+ _vm->_screen->blitFrom(*_savedSurface, _position);
delete _savedSurface;
_savedSurface = nullptr;
- _vm->_screen.copyRectToScreen(getBounds());
-
Common::copy(&_dialogPalette[0], &_dialogPalette[8 * 3],
&_vm->_palette->_mainPalette[248 * 3]);
_vm->_palette->setPalette(&_vm->_palette->_mainPalette[248 * 3], 248, 8);
@@ -87,16 +85,16 @@ void Dialog::draw() {
// Draw the dialog
// Fill entire content of dialog
Common::Rect bounds = getBounds();
- _vm->_screen.fillRect(bounds, TEXTDIALOG_BACKGROUND);
+ _vm->_screen->fillRect(bounds, TEXTDIALOG_BACKGROUND);
// Draw the outer edge lines
- _vm->_screen.hLine(_position.x + 1, _position.y + _height - 2,
+ _vm->_screen->hLine(_position.x + 1, _position.y + _height - 2,
_position.x + _width - 2, TEXTDIALOG_EDGE);
- _vm->_screen.hLine(_position.x, _position.y + _height - 1,
+ _vm->_screen->hLine(_position.x, _position.y + _height - 1,
_position.x + _width - 1, TEXTDIALOG_EDGE);
- _vm->_screen.vLine(_position.x + _width - 2, _position.y + 2,
+ _vm->_screen->vLine(_position.x + _width - 2, _position.y + 2,
_position.y + _height - 2, TEXTDIALOG_EDGE);
- _vm->_screen.vLine(_position.x + _width - 1, _position.y + 1,
+ _vm->_screen->vLine(_position.x + _width - 1, _position.y + 1,
_position.y + _height - 1, TEXTDIALOG_EDGE);
// Draw the gravelly dialog content
@@ -125,8 +123,9 @@ void Dialog::calculateBounds() {
void Dialog::drawContent(const Common::Rect &r, int seed, byte color1, byte color2) {
uint16 currSeed = seed ? seed : 0xB78E;
+ Graphics::Surface dest = _vm->_screen->getSubArea(r);
for (int yp = 0; yp < r.height(); ++yp) {
- byte *destP = _vm->_screen.getBasePtr(r.left, r.top + yp);
+ byte *destP = (byte *)dest.getBasePtr(0, yp);
for (int xp = 0; xp < r.width(); ++xp) {
uint16 seedAdjust = currSeed;
@@ -326,7 +325,7 @@ void TextDialog::draw() {
for (int lineNum = 0; lineNum <= _numLines; ++lineNum) {
if (_lineXp[lineNum] == -1) {
// Draw a line across the entire dialog
- _vm->_screen.hLine(_position.x + 2,
+ _vm->_screen->hLine(_position.x + 2,
lineYp + (_font->getHeight() + 1) / 2,
_position.x + _width - 4, TEXTDIALOG_BLACK);
} else {
@@ -336,21 +335,19 @@ void TextDialog::draw() {
if (_lineXp[lineNum] & 0x40)
++yp;
- _font->writeString(&_vm->_screen, _lines[lineNum],
+ _font->writeString(_vm->_screen, _lines[lineNum],
Common::Point(xp, yp), 1);
if (_lineXp[lineNum] & 0x80) {
// Draw an underline under the text
int lineWidth = _font->getWidth(_lines[lineNum], 1);
- _vm->_screen.hLine(xp, yp + _font->getHeight(), xp + lineWidth,
+ _vm->_screen->hLine(xp, yp + _font->getHeight(), xp + lineWidth,
TEXTDIALOG_BLACK);
}
}
lineYp += _font->getHeight() + 1;
}
-
- _vm->_screen.copyRectToScreen(getBounds());
}
void TextDialog::calculateBounds() {
@@ -360,10 +357,10 @@ void TextDialog::calculateBounds() {
if (_position.y == -1)
_position.y = 100 - (_height / 2);
- if ((_position.x + _width) > _vm->_screen.getWidth())
- _position.x = _vm->_screen.getWidth() - (_position.x + _width);
- if ((_position.y + _height) > _vm->_screen.getHeight())
- _position.y = _vm->_screen.getHeight() - (_position.y + _height);
+ if ((_position.x + _width) > _vm->_screen->w)
+ _position.x = _vm->_screen->w - (_position.x + _width);
+ if ((_position.y + _height) > _vm->_screen->h)
+ _position.y = _vm->_screen->h - (_position.y + _height);
}
void TextDialog::drawWithInput() {
@@ -452,7 +449,7 @@ FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
}
FullScreenDialog::~FullScreenDialog() {
- _vm->_screen.resetClipBounds();
+ _vm->_screen->resetClipBounds();
_vm->_game->_scene.restrictScene();
}
@@ -491,16 +488,13 @@ void FullScreenDialog::display() {
game._trigger = 0;
// Clear the screen and draw the upper and lower horizontal lines
- _vm->_screen.empty();
+ _vm->_screen->clear();
_vm->_palette->setLowRange();
- _vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
- _vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
- _vm->_screen.resetClipBounds();
- _vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+ _vm->_screen->hLine(0, 20, MADS_SCREEN_WIDTH, 2);
+ _vm->_screen->hLine(0, 179, MADS_SCREEN_WIDTH, 2);
// Restrict the screen to the area between the two lines
- _vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH,
- DIALOG_TOP + MADS_SCENE_HEIGHT));
+ _vm->_screen->setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH, DIALOG_TOP + MADS_SCENE_HEIGHT));
_vm->_game->_scene.restrictScene();
if (_screenId > 0)
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.cpp b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
index 938931e80d..c20eeb72fa 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.cpp
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.cpp
@@ -201,7 +201,7 @@ Common::String DragonsphereScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, int variant) {
Common::String ext = Common::String::format(".WW%d", variant);
Common::String fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
if (!Common::File::exists(fileName))
@@ -217,8 +217,8 @@ void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoDragonsphere::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
- byte *destP = depthSurface.getData();
+void SceneInfoDragonsphere::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
+ byte *destP = (byte *)depthSurface.getPixels();
byte *walkMap = new byte[stream->size()];
stream->read(walkMap, stream->size());
diff --git a/engines/mads/dragonsphere/dragonsphere_scenes.h b/engines/mads/dragonsphere/dragonsphere_scenes.h
index e9b48715db..22d894b9d9 100644
--- a/engines/mads/dragonsphere/dragonsphere_scenes.h
+++ b/engines/mads/dragonsphere/dragonsphere_scenes.h
@@ -647,9 +647,9 @@ public:
class SceneInfoDragonsphere : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp
index 7463704c4b..de83260b0f 100644
--- a/engines/mads/events.cpp
+++ b/engines/mads/events.cpp
@@ -98,7 +98,7 @@ void EventsManager::changeCursor() {
// Check for hotspot indication pixels along the right-hand and bottom
// row. Put together, these give the cursor's hotspot x,y
int hotspotX = 0, hotspotY = 0;
- byte *cursorData = cursor->getData();
+ const byte *cursorData = (const byte *)cursor->getPixels();
for (int idx = 0; idx < cursor->w; ++idx) {
if (cursorData[(cursor->h - 1) * cursor->w + idx] != transIndex)
hotspotX = idx;
@@ -110,7 +110,7 @@ void EventsManager::changeCursor() {
// Reduce the cursor data to remove the last column from each row, since
// the cursor routines don't have a pitch option
byte *destCursor = new byte[(cursor->w - 1) * (cursor->h - 1)];
- byte *srcP = cursorData;
+ const byte *srcP = cursorData;
byte *destP = destCursor;
for (int idx = 0; idx < (cursor->h - 1); ++idx) {
@@ -217,7 +217,7 @@ bool EventsManager::checkForNextFrameCounter() {
_vm->_debugger->onFrame();
// Display the frame
- _vm->_screen.updateScreen();
+ _vm->_screen->update();
// Signal the ScummVM debugger
_vm->_debugger->onFrame();
diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp
index 3e6d23fe6f..684418da91 100644
--- a/engines/mads/font.cpp
+++ b/engines/mads/font.cpp
@@ -145,7 +145,7 @@ void Font::setColorMode(SelectionMode mode) {
}
}
-int Font::writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+int Font::writeString(BaseSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth, int width) {
int xEnd;
if (width > 0)
@@ -167,16 +167,13 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common
return x;
int bottom = y + height - 1;
- if (bottom > surface->getHeight() - 1) {
- height -= MIN(height, bottom - (surface->getHeight() - 1));
+ if (bottom > surface->h - 1) {
+ height -= MIN(height, bottom - (surface->h - 1));
}
if (height <= 0)
return x;
- byte *destPtr = surface->getBasePtr(x, y);
- uint8 *oldDestPtr = destPtr;
-
int xPos = x;
const char *text = msg.c_str();
@@ -185,10 +182,11 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common
int charWidth = _charWidths[(byte)theChar];
if (charWidth > 0) {
-
if (xPos + charWidth > xEnd)
return xPos;
+ Graphics::Surface dest = surface->getSubArea(
+ Common::Rect(xPos, y, xPos + charWidth, y + height));
uint8 *charData = &_charData[_charOffs[(byte)theChar]];
int bpp = getBpp(charWidth);
@@ -196,6 +194,8 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common
charData += bpp * skipY;
for (int i = 0; i < height; i++) {
+ byte *destPtr = (byte *)dest.getBasePtr(0, i);
+
for (int j = 0; j < bpp; j++) {
if (*charData & 0xc0)
*destPtr = _fontColors[(*charData & 0xc0) >> 6];
@@ -211,22 +211,13 @@ int Font::writeString(MSurface *surface, const Common::String &msg, const Common
destPtr++;
charData++;
}
-
- destPtr += surface->getWidth() - bpp * 4;
-
}
-
- destPtr = oldDestPtr + charWidth + spaceWidth;
- oldDestPtr = destPtr;
-
}
xPos += charWidth + spaceWidth;
-
}
return xPos;
-
}
int Font::getWidth(const Common::String &msg, int spaceWidth) {
diff --git a/engines/mads/font.h b/engines/mads/font.h
index 486cadcfff..a27de6e283 100644
--- a/engines/mads/font.h
+++ b/engines/mads/font.h
@@ -86,7 +86,7 @@ public:
int maxWidth() const { return _maxWidth; }
int getWidth(const Common::String &msg, int spaceWidth = -1);
int getHeight() const { return _maxHeight; }
- int writeString(MSurface *surface, const Common::String &msg, const Common::Point &pt,
+ int writeString(BaseSurface *surface, const Common::String &msg, const Common::Point &pt,
int spaceWidth = 0, int width = 0);
};
diff --git a/engines/mads/game.cpp b/engines/mads/game.cpp
index 8ebea2a3b2..0a6741ba7a 100644
--- a/engines/mads/game.cpp
+++ b/engines/mads/game.cpp
@@ -498,7 +498,7 @@ void Game::loadGame(int slotNumber) {
_scene._currentSceneId = -2;
_sectionNumber = _scene._nextSceneId / 100;
_scene._frameStartTime = _vm->_events->getFrameCounter();
- _vm->_screen._shakeCountdown = -1;
+ _vm->_screen->_shakeCountdown = -1;
// Default the selected inventory item to the first one, if the player has any
_scene._userInterface._selectedInvIndex = _objects._inventoryList.size() > 0 ? 0 : -1;
@@ -600,7 +600,8 @@ void Game::createThumbnail() {
uint8 thumbPalette[PALETTE_SIZE];
_vm->_palette->grabPalette(thumbPalette, 0, PALETTE_COUNT);
_saveThumb = new Graphics::Surface();
- ::createThumbnail(_saveThumb, _vm->_screen.getData(), MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette);
+ ::createThumbnail(_saveThumb, (const byte *)_vm->_screen->getPixels(),
+ MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT, thumbPalette);
}
void Game::syncTimers(SyncType slaveType, int slaveId, SyncType masterType, int masterId) {
diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp
index deccb5ba4f..5776d813cf 100644
--- a/engines/mads/mads.cpp
+++ b/engines/mads/mads.cpp
@@ -58,6 +58,7 @@ MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
_resources = nullptr;
_sound = nullptr;
_audio = nullptr;
+ _screen = nullptr;
}
MADSEngine::~MADSEngine() {
@@ -94,7 +95,7 @@ void MADSEngine::initialize() {
_palette = new Palette(this);
Font::init(this);
_font = new Font();
- _screen.init();
+ _screen = new Screen();
_sound = new SoundManager(this, _mixer);
_audio = new AudioPlayer(_mixer, getGameID());
_game = Game::init(this);
@@ -102,7 +103,7 @@ void MADSEngine::initialize() {
loadOptions();
- _screen.empty();
+ _screen->clear();
}
void MADSEngine::loadOptions() {
diff --git a/engines/mads/mads.h b/engines/mads/mads.h
index eb808de32f..52f71f7c79 100644
--- a/engines/mads/mads.h
+++ b/engines/mads/mads.h
@@ -100,7 +100,7 @@ public:
GameConversations * _gameConv;
Palette *_palette;
Resources *_resources;
- ScreenSurface _screen;
+ Screen *_screen;
SoundManager *_sound;
AudioPlayer *_audio;
bool _easyMouse;
diff --git a/engines/mads/menu_views.cpp b/engines/mads/menu_views.cpp
index 10d5a2179a..9050ca6081 100644
--- a/engines/mads/menu_views.cpp
+++ b/engines/mads/menu_views.cpp
@@ -253,7 +253,7 @@ void TextView::processCommand() {
SceneInfo *sceneInfo = SceneInfo::init(_vm);
sceneInfo->_width = MADS_SCREEN_WIDTH;
sceneInfo->_height = MADS_SCENE_HEIGHT;
- _spareScreens[spareIndex].setSize(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
+ _spareScreens[spareIndex].create(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT);
sceneInfo->loadMadsV1Background(screenId, "", SCENEFLAG_TRANSLATE,
_spareScreens[spareIndex]);
@@ -346,9 +346,11 @@ void TextView::doFrame() {
// If a screen transition is in progress and it's time for another column, handle it
if (_spareScreen) {
- byte *srcP = _spareScreen->getBasePtr(_translationX, 0);
- byte *bgP = scene._backgroundSurface.getBasePtr(_translationX, 0);
- byte *screenP = (byte *)_vm->_screen.getBasePtr(_translationX, 0);
+ const byte *srcP = (const byte *)_spareScreen->getBasePtr(_translationX, 0);
+ byte *bgP = (byte *)scene._backgroundSurface.getBasePtr(_translationX, 0);
+
+ Graphics::Surface dest = _vm->_screen->getSubArea(Common::Rect(_translationX, 0, _translationX + 1, 0));
+ byte *screenP = (byte *)dest.getBasePtr(0, 0);
for (int y = 0; y < MADS_SCENE_HEIGHT; ++y, srcP += MADS_SCREEN_WIDTH,
bgP += MADS_SCREEN_WIDTH, screenP += MADS_SCREEN_WIDTH) {
@@ -356,10 +358,6 @@ void TextView::doFrame() {
*screenP = *srcP;
}
- // Flag the column of the screen is modified
- _vm->_screen.copyRectToScreen(Common::Rect(_translationX, 0,
- _translationX + 1, MADS_SCENE_HEIGHT));
-
// Keep moving the column to copy to the right
if (++_translationX == MADS_SCREEN_WIDTH) {
// Surface transition is complete
@@ -571,6 +569,7 @@ void AnimationView::doFrame() {
void AnimationView::loadNextResource() {
Scene &scene = _vm->_game->_scene;
Palette &palette = *_vm->_palette;
+ Screen &screen = *_vm->_screen;
ResourceEntry &resEntry = _resources[_resourceIndex];
Common::Array<PaletteCycle> paletteCycles;
@@ -587,12 +586,15 @@ void AnimationView::loadNextResource() {
// Handle the bars at the top/bottom
if (resEntry._showWhiteBars) {
// For animations the screen has been clipped to the middle 156 rows.
- // So although it's slightly messy, bypass our screen class entirely,
- // and draw the horizontal lines directly on the physiacl screen surface
- Graphics::Surface *s = g_system->lockScreen();
- s->hLine(0, 20, MADS_SCREEN_WIDTH, 253);
- s->hLine(0, 179, MADS_SCREEN_WIDTH, 253);
- g_system->unlockScreen();
+ // So although it's slightly messy, temporarily reset clip bounds
+ // so we can redraw the white lines
+ Common::Rect clipBounds = screen.getClipBounds();
+ screen.resetClipBounds();
+
+ screen.hLine(0, 20, MADS_SCREEN_WIDTH, 253);
+ screen.hLine(0, 179, MADS_SCREEN_WIDTH, 253);
+
+ screen.setClipBounds(clipBounds);
}
// Load the new animation
diff --git a/engines/mads/menu_views.h b/engines/mads/menu_views.h
index c203248ad9..e22b6223a7 100644
--- a/engines/mads/menu_views.h
+++ b/engines/mads/menu_views.h
@@ -8,20 +8,12 @@
* 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.
-<<<<<<< HEAD
-
-=======
*
->>>>>>> master
* 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.
-<<<<<<< HEAD
-
-=======
*
->>>>>>> master
* 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.
diff --git a/engines/mads/messages.cpp b/engines/mads/messages.cpp
index 2bee77dae7..773ebd309c 100644
--- a/engines/mads/messages.cpp
+++ b/engines/mads/messages.cpp
@@ -558,7 +558,7 @@ void TextDisplayList::setDirtyAreas2() {
}
}
-void TextDisplayList::draw(MSurface *s) {
+void TextDisplayList::draw(BaseSurface *s) {
for (uint idx = 0; idx < size(); ++idx) {
TextDisplay &td = (*this)[idx];
if (td._active && (td._expire >= 0)) {
diff --git a/engines/mads/messages.h b/engines/mads/messages.h
index 2b673a8a4d..ced8c5bb6d 100644
--- a/engines/mads/messages.h
+++ b/engines/mads/messages.h
@@ -170,7 +170,7 @@ public:
* Draw any text in the list to the specified surface
* @param surface Surface
*/
- void draw(MSurface *s);
+ void draw(BaseSurface *s);
/**
* Determine dirty areas for active text areas
diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp
index f768624278..8ea9c39bf5 100644
--- a/engines/mads/msurface.cpp
+++ b/engines/mads/msurface.cpp
@@ -30,40 +30,9 @@
namespace MADS {
-MADSEngine *MSurface::_vm = nullptr;
+MADSEngine *BaseSurface::_vm = nullptr;
-MSurface::MSurface() {
- pixels = nullptr;
- _freeFlag = false;
-}
-
-MSurface::MSurface(int width, int height) {
- pixels = nullptr;
- _freeFlag = false;
- setSize(width, height);
-}
-
-MSurface::~MSurface() {
- if (_freeFlag)
- Graphics::Surface::free();
-}
-
-void MSurface::setSize(int width, int height) {
- if (_freeFlag)
- Graphics::Surface::free();
- Graphics::Surface::create(width, height, Graphics::PixelFormat::createFormatCLUT8());
- _freeFlag = true;
-}
-
-void MSurface::setPixels(byte *pData, int horizSize, int vertSize) {
- _freeFlag = false;
- pixels = pData;
- w = pitch = horizSize;
- h = vertSize;
- format.bytesPerPixel = 1;
-}
-
-int MSurface::scaleValue(int value, int scale, int err) {
+int BaseSurface::scaleValue(int value, int scale, int err) {
int scaled = 0;
while (value--) {
err -= scale;
@@ -75,8 +44,7 @@ int MSurface::scaleValue(int value, int scale, int err) {
return scaled;
}
-void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
-
+void BaseSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect) {
enum {
kStatusSkip,
kStatusScale,
@@ -116,8 +84,8 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
return;
int heightAmt = scaledHeight;
- byte *src = info.sprite->getData();
- byte *dst = getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY);
+ const byte *src = (const byte *)info.sprite->getPixels();
+ byte *dst = (byte *)getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY);
int status = kStatusSkip;
byte *scaledLineBuf = new byte[scaledWidth];
@@ -138,7 +106,7 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
byte *lineDst = scaledLineBuf;
int curErrX = errX;
int width = scaledWidth;
- byte *tempSrc = src;
+ const byte *tempSrc = src;
int startX = clipX;
while (width > 0) {
byte pixel = *tempSrc++;
@@ -201,63 +169,136 @@ void MSurface::drawSprite(const Common::Point &pt, SpriteInfo &info, const Commo
}
delete[] scaledLineBuf;
-
}
-void MSurface::empty() {
- Common::fill(getBasePtr(0, 0), getBasePtr(0, h), 0);
+void BaseSurface::scrollX(int xAmount) {
+ if (xAmount == 0)
+ return;
+
+ byte buffer[80];
+ int direction = (xAmount > 0) ? -1 : 1;
+ int xSize = ABS(xAmount);
+ assert(xSize <= 80);
+
+ byte *srcP = (byte *)getBasePtr(0, 0);
+
+ for (int y = 0; y < this->h; ++y, srcP += pitch) {
+ if (direction < 0) {
+ // Copy area to be overwritten
+ Common::copy(srcP, srcP + xSize, &buffer[0]);
+ // Shift the remainder of the line over the given area
+ Common::copy(srcP + xSize, srcP + this->w, srcP);
+ // Move buffered area to the end of the line
+ Common::copy(&buffer[0], &buffer[xSize], srcP + this->w - xSize);
+ } else {
+ // Copy area to be overwritten
+ Common::copy_backward(srcP + this->w - xSize, srcP + this->w, &buffer[80]);
+ // Shift the remainder of the line over the given area
+ Common::copy_backward(srcP, srcP + this->w - xSize, srcP + this->w);
+ // Move buffered area to the start of the line
+ Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize);
+ }
+ }
+
+ markAllDirty();
}
-void MSurface::copyFrom(MSurface *src, const Common::Rect &srcBounds,
- const Common::Point &destPos, int transparentColor) {
- // Validation of the rectangle and position
- int destX = destPos.x, destY = destPos.y;
- if ((destX >= w) || (destY >= h))
+void BaseSurface::scrollY(int yAmount) {
+ if (yAmount == 0)
return;
- Common::Rect copyRect = srcBounds;
- if (destX < 0) {
- copyRect.left += -destX;
- destX = 0;
- } else if (destX + copyRect.width() > w) {
- copyRect.right -= destX + copyRect.width() - w;
- }
- if (destY < 0) {
- copyRect.top += -destY;
- destY = 0;
- } else if (destY + copyRect.height() > h) {
- copyRect.bottom -= destY + copyRect.height() - h;
+ int direction = (yAmount > 0) ? 1 : -1;
+ int ySize = ABS(yAmount);
+ assert(ySize < (this->h / 2));
+ assert(this->w == pitch);
+
+ int blockSize = ySize * this->w;
+ byte *tempData = new byte[blockSize];
+ byte *pixelsP = (byte *)getBasePtr(0, 0);
+
+ if (direction > 0) {
+ // Buffer the lines to be overwritten
+ byte *srcP = (byte *)getBasePtr(0, this->h - ySize);
+ Common::copy(srcP, srcP + (pitch * ySize), tempData);
+ // Vertically shift all the lines
+ Common::copy_backward(pixelsP, pixelsP + (pitch * (this->h - ySize)),
+ pixelsP + (pitch * this->h));
+ // Transfer the buffered lines top the top of the screen
+ Common::copy(tempData, tempData + blockSize, pixelsP);
+ } else {
+ // Buffer the lines to be overwritten
+ Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData);
+ // Vertically shift all the lines
+ Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * this->h), pixelsP);
+ // Transfer the buffered lines to the bottom of the screen
+ Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (this->h - ySize)));
}
- if (!copyRect.isValidRect())
- return;
+ markAllDirty();
+ delete[] tempData;
+}
- // Copy the specified area
+void BaseSurface::translate(Common::Array<RGB6> &palette) {
+ for (int y = 0; y < this->h; ++y) {
+ byte *pDest = (byte *)getBasePtr(0, y);
- byte *data = src->getData();
- byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
- byte *destPtr = (byte *)pixels + (destY * getWidth()) + destX;
+ for (int x = 0; x < this->w; ++x, ++pDest) {
+ if (*pDest < 255) // scene 752 has some palette indices of 255
+ *pDest = palette[*pDest]._palIndex;
+ }
+ }
- for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
- if (transparentColor == -1) {
- // No transparency, so copy line over
- Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr);
- } else {
- // Copy each byte one at a time checking for the transparency color
- for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr)
- if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr];
+ markAllDirty();
+}
+
+void BaseSurface::translate(byte map[PALETTE_COUNT]) {
+ for (int y = 0; y < this->h; ++y) {
+ byte *pDest = (byte *)getBasePtr(0, y);
+
+ for (int x = 0; x < this->w; ++x, ++pDest) {
+ *pDest = map[*pDest];
}
+ }
+
+ markAllDirty();
+}
+
+BaseSurface *BaseSurface::flipHorizontal() const {
+ MSurface *dest = new MSurface(this->w, this->h);
+
+ for (int y = 0; y < this->h; ++y) {
+ const byte *srcP = getBasePtr(this->w - 1, y);
+ byte *destP = dest->getBasePtr(0, y);
- srcPtr += src->getWidth();
- destPtr += getWidth();
+ for (int x = 0; x < this->w; ++x)
+ *destP++ = *srcP--;
+ }
+
+ return dest;
+}
+
+void BaseSurface::copyRectTranslate(BaseSurface &srcSurface, const byte *paletteMap,
+ const Common::Point &destPos, const Common::Rect &srcRect) {
+ // Loop through the lines
+ for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
+ const byte *srcP = (const byte *)srcSurface.getBasePtr(srcRect.left, srcRect.top + yCtr);
+ byte *destP = (byte *)getBasePtr(destPos.x, destPos.y + yCtr);
+
+ // Copy the line over
+ for (int xCtr = 0; xCtr < srcRect.width(); ++xCtr, ++srcP, ++destP) {
+ *destP = paletteMap[*srcP];
+ }
}
+
+ addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + srcRect.width(),
+ destPos.y + srcRect.height()));
}
-void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
+void BaseSurface::copyFrom(BaseSurface &src, const Common::Point &destPos, int depth,
DepthSurface *depthSurface, int scale, bool flipped, int transparentColor) {
int destX = destPos.x, destY = destPos.y;
- int frameWidth = src->getWidth();
- int frameHeight = src->getHeight();
+ int frameWidth = src.w;
+ int frameHeight = src.h;
int direction = flipped ? -1 : 1;
int highestDim = MAX(frameWidth, frameHeight);
@@ -271,7 +312,8 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
distCtr += scale;
if (distCtr < 100) {
lineDist[distIndex] = false;
- } else {
+ }
+ else {
lineDist[distIndex] = true;
distCtr -= 100;
@@ -290,7 +332,7 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
// Special case for quicker drawing of non-scaled images
if (scale == 100 || scale == -1) {
// Copy the specified area
- Common::Rect copyRect(0, 0, src->getWidth(), src->getHeight());
+ Common::Rect copyRect(0, 0, src.w, src.h);
if (destX < 0) {
copyRect.left += -destX;
@@ -311,9 +353,9 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
if (flipped)
copyRect.moveTo(0, copyRect.top);
- byte *data = src->getData();
- byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
- byte *destPtr = (byte *)pixels + (destY * pitch) + destX;
+ byte *data = src.getPixels();
+ byte *srcPtr = data + (src.w * copyRect.top + copyRect.left);
+ byte *destPtr = (byte *)getPixels() + (destY * pitch) + destX;
if (flipped)
srcPtr += copyRect.width() - 1;
@@ -329,18 +371,18 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
destPtr[xCtr] = *srcP;
}
- srcPtr += src->getWidth();
- destPtr += getWidth();
+ srcPtr += src.w;
+ destPtr += this->w;
}
return;
}
// Start of draw logic for scaled sprites
- const byte *srcPixelsP = src->getData();
+ const byte *srcPixelsP = src.getPixels();
- int destRight = this->getWidth() - 1;
- int destBottom = this->getHeight() - 1;
+ int destRight = this->w - 1;
+ int destBottom = this->h - 1;
// Check x bounding area
int spriteLeft = 0;
@@ -387,7 +429,7 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
spriteLeft = spriteLeft * direction;
// Loop through the lines of the sprite
- for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src->pitch) {
+ for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += src.pitch) {
if (!lineDist[yp])
// Not a display line, so skip it
continue;
@@ -411,8 +453,8 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
continue;
// Get depth of current output pixel in depth surface
- Common::Point pt((destP - (byte *)this->pixels) % this->pitch,
- (destP - (byte *)this->pixels) / this->pitch);
+ Common::Point pt((destP - (byte *)getPixels()) % this->pitch,
+ (destP - (byte *)getPixels()) / this->pitch);
int pixelDepth = (depthSurface == nullptr) ? 15 : depthSurface->getDepth(pt);
if ((*srcP != transparentColor) && (depth <= pixelDepth))
@@ -424,119 +466,8 @@ void MSurface::copyFrom(MSurface *src, const Common::Point &destPos, int depth,
// Move to the next destination line
destPixelsP += this->pitch;
}
-}
-
-void MSurface::scrollX(int xAmount) {
- if (xAmount == 0)
- return;
-
- byte buffer[80];
- int direction = (xAmount > 0) ? -1 : 1;
- int xSize = ABS(xAmount);
- assert(xSize <= 80);
- byte *srcP = getBasePtr(0, 0);
-
- for (int y = 0; y < this->h; ++y, srcP += pitch) {
- if (direction < 0) {
- // Copy area to be overwritten
- Common::copy(srcP, srcP + xSize, &buffer[0]);
- // Shift the remainder of the line over the given area
- Common::copy(srcP + xSize, srcP + this->w, srcP);
- // Move buffered area to the end of the line
- Common::copy(&buffer[0], &buffer[xSize], srcP + this->w - xSize);
- } else {
- // Copy area to be overwritten
- Common::copy_backward(srcP + this->w - xSize, srcP + this->w, &buffer[80]);
- // Shift the remainder of the line over the given area
- Common::copy_backward(srcP, srcP + this->w - xSize, srcP + this->w);
- // Move buffered area to the start of the line
- Common::copy_backward(&buffer[80 - xSize], &buffer[80], srcP + xSize);
- }
- }
-}
-
-void MSurface::scrollY(int yAmount) {
- if (yAmount == 0)
- return;
-
- int direction = (yAmount > 0) ? 1 : -1;
- int ySize = ABS(yAmount);
- assert(ySize < (this->h / 2));
- assert(this->w == pitch);
-
- int blockSize = ySize * this->w;
- byte *tempData = new byte[blockSize];
- byte *pixelsP = getBasePtr(0, 0);
-
- if (direction > 0) {
- // Buffer the lines to be overwritten
- byte *srcP = (byte *)getBasePtr(0, this->h - ySize);
- Common::copy(srcP, srcP + (pitch * ySize), tempData);
- // Vertically shift all the lines
- Common::copy_backward(pixelsP, pixelsP + (pitch * (this->h - ySize)),
- pixelsP + (pitch * this->h));
- // Transfer the buffered lines top the top of the screen
- Common::copy(tempData, tempData + blockSize, pixelsP);
- } else {
- // Buffer the lines to be overwritten
- Common::copy(pixelsP, pixelsP + (pitch * ySize), tempData);
- // Vertically shift all the lines
- Common::copy(pixelsP + (pitch * ySize), pixelsP + (pitch * this->h), pixelsP);
- // Transfer the buffered lines to the bottom of the screen
- Common::copy(tempData, tempData + blockSize, pixelsP + (pitch * (this->h - ySize)));
- }
-
- delete[] tempData;
-}
-
-void MSurface::translate(Common::Array<RGB6> &palette) {
- for (int y = 0; y < this->h; ++y) {
- byte *pDest = getBasePtr(0, y);
-
- for (int x = 0; x < this->w; ++x, ++pDest) {
- if (*pDest < 255) // scene 752 has some palette indices of 255
- *pDest = palette[*pDest]._palIndex;
- }
- }
-}
-
-void MSurface::translate(byte map[PALETTE_COUNT]) {
- for (int y = 0; y < this->h; ++y) {
- byte *pDest = getBasePtr(0, y);
-
- for (int x = 0; x < this->w; ++x, ++pDest) {
- *pDest = map[*pDest];
- }
- }
-}
-
-MSurface *MSurface::flipHorizontal() const {
- MSurface *dest = new MSurface(this->w, this->h);
-
- for (int y = 0; y < this->h; ++y) {
- const byte *srcP = getBasePtr(this->w - 1, y);
- byte *destP = dest->getBasePtr(0, y);
-
- for (int x = 0; x < this->w; ++x)
- *destP++ = *srcP--;
- }
-
- return dest;
-}
-
-void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
- const Common::Point &destPos, const Common::Rect &srcRect) {
- // Loop through the lines
- for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
- const byte *srcP = srcSurface.getBasePtr(srcRect.left, srcRect.top + yCtr);
- byte *destP = getBasePtr(destPos.x, destPos.y + yCtr);
-
- // Copy the line over
- for (int xCtr = 0; xCtr < srcRect.width(); ++xCtr, ++srcP, ++destP) {
- *destP = paletteMap[*srcP];
- }
- }
+ addDirtyRect(Common::Rect(destX, destY, destX + frameWidth, destY + frameHeight));
}
/*------------------------------------------------------------------------*/
@@ -544,26 +475,26 @@ void MSurface::copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
int DepthSurface::getDepth(const Common::Point &pt) {
if (_depthStyle == 2) {
int bits = (3 - (pt.x % 4)) * 2;
- byte v = *getBasePtr(pt.x >> 2, pt.y);
+ byte v = *(const byte *)getBasePtr(pt.x >> 2, pt.y);
return v >> bits;
} else {
if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h)
return 0;
- return *getBasePtr(pt.x, pt.y) & 0xF;
+ return *(const byte *)getBasePtr(pt.x, pt.y) & 0xF;
}
}
int DepthSurface::getDepthHighBit(const Common::Point &pt) {
if (_depthStyle == 2) {
int bits = (3 - (pt.x % 4)) * 2;
- byte v = *getBasePtr(pt.x >> 2, pt.y);
+ byte v = *(const byte *)getBasePtr(pt.x >> 2, pt.y);
return (v >> bits) & 2;
} else {
if (pt.x < 0 || pt.y < 0 || pt.x >= this->w || pt.y >= this->h)
return 0;
- return *getBasePtr(pt.x, pt.y) & 0x80;
+ return *(const byte *)getBasePtr(pt.x, pt.y) & 0x80;
}
}
diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h
index 8930737b0a..5b5a1d62c1 100644
--- a/engines/mads/msurface.h
+++ b/engines/mads/msurface.h
@@ -25,7 +25,7 @@
#include "common/scummsys.h"
#include "common/rect.h"
-#include "graphics/surface.h"
+#include "graphics/screen.h"
#include "mads/palette.h"
namespace MADS {
@@ -48,12 +48,18 @@ struct SpriteInfo {
};
/*
- * MADS graphics surface
+ * Base MADS surface class. This derivces from Graphics::Screen
+ * because it has logic we'll need for our own Screen class that
+ * derives from this one
*/
-class MSurface : public Graphics::Surface {
+class BaseSurface : public Graphics::Screen {
+private:
+ /**
+ * Helper method for calculating new dimensions when scaling a sprite
+ */
+ int scaleValue(int value, int scale, int err);
protected:
static MADSEngine *_vm;
- bool _freeFlag;
public:
/**
* Sets the engine reference used all surfaces
@@ -61,11 +67,6 @@ public:
static void setVm(MADSEngine *vm) { _vm = vm; }
/**
- * Helper method for calculating new dimensions when scaling a sprite
- */
- static int scaleValue(int value, int scale, int err);
-
- /**
* Base method for descendents to load their contents
*/
virtual void load(const Common::String &resName) {}
@@ -73,126 +74,52 @@ public:
/**
* Basic constructor
*/
- MSurface();
+ BaseSurface() : Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
+ }
/**
* Constructor for a surface with fixed dimensions
*/
- MSurface(int width, int height);
+ BaseSurface(int width, int height) : Graphics::Screen(width, height) {}
/**
* Destructor
*/
- virtual ~MSurface();
-
- /**
- * Reinitializes a surface to have a given set of dimensions
- */
- void setSize(int width, int height);
-
- /**
- * Sets the pixels the surface is associated with
- * @remarks The surface will not free the data block
- */
- void setPixels(byte *pData, int horizSize, int vertSize);
-
- /**
- * Draws an arbitrary line on the screen using a specified color
- * @param startPos Starting position
- * @param endPos Ending position
- * @param color Color to use
- */
- void line(const Common::Point &startPos, const Common::Point &endPos, byte color);
-
- /**
- * Draws a sprite
- * @param pt Position to draw sprite at
- * @param info General sprite details
- * @param clipRect Clipping rectangle to constrain sprite drawing within
- */
- void drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect);
-
- /**
- * Returns the width of the surface
- */
- int getWidth() const { return w; }
+ virtual ~BaseSurface() {}
/**
- * Returns the height of the surface
+ * Return a rect containing the bounds of the surface
*/
- int getHeight() const { return h; }
+ Common::Rect getBounds() { return Common::Rect(0, 0, this->w, this->h); }
/**
- * Returns the size of the surface as a Rect
+ * Return the pixels for the surface
*/
- Common::Rect getBounds() const {
- return Common::Rect(0, 0, w, h);
- }
+ inline byte *getPixels() { return (byte *)Graphics::ManagedSurface::getPixels(); }
/**
- * Returns a pointer to the surface data
+ * Return the pixels for the surface
*/
- byte *getData() { return (byte *)Graphics::Surface::getPixels(); }
+ inline const void *getPixels() const { return (const byte *)Graphics::ManagedSurface::getPixels(); }
/**
- * Returns a pointer to a given position within the surface
+ * Return a pointer to a given position on the surface
*/
- byte *getBasePtr(int x, int y) { return (byte *)Graphics::Surface::getBasePtr(x, y); }
-
- /**
- * Returns a pointer to a given position within the surface
- */
- const byte *getBasePtr(int x, int y) const { return (const byte *)Graphics::Surface::getBasePtr(x, y); }
+ byte *getBasePtr(int x, int y) { return (byte *)Graphics::ManagedSurface::getBasePtr(x, y); }
/**
- * Clears the surface
+ * Return a pointer to a given position on the surface
*/
- void empty();
+ inline const byte *getBasePtr(int x, int y) const { return (const byte *)Graphics::ManagedSurface::getBasePtr(x, y); }
/**
- * Copys a sub-section of another surface into the current one.
- * @param src Source surface
- * @param srcBounds Area of source surface to copy
- * @param destPos Destination position to draw in current surface
- * @param transparentColor Transparency palette index
- */
- void copyFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
- int transparentColor = -1);
-
- /**
- * Copys a sub-section of another surface into the current one.
- * @param src Source surface
- * @param destPos Destination position to draw in current surface
- * @param depth Depth of sprite
- * @param depthSurface Depth surface to use with sprite depth
- * @param scale Scale for image
- * @param flipped Flag for whether image is to be flipped
- * @param transparentColor Transparency palette index
- */
- void copyFrom(MSurface *src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
- int scale, bool flipped, int transparentColor = -1);
-
- /**
- * Copies the surface to a given destination surface
- */
- void copyTo(MSurface *dest, int transparentColor = -1) {
- dest->copyFrom(this, Common::Rect(w, h), Common::Point(), transparentColor);
- }
-
- /**
- * Copies the surface to a given destination surface
- */
- void copyTo(MSurface *dest, const Common::Point &pt, int transparentColor = -1) {
- dest->copyFrom(this, Common::Rect(w, h), pt, transparentColor);
- }
-
- /**
- * Copies the surface to a given destination surface
+ * Draws a sprite
+ * @param pt Position to draw sprite at
+ * @param info General sprite details
+ * @param clipRect Clipping rectangle to constrain sprite drawing within
*/
- void copyTo(MSurface *dest, const Common::Rect &srcBounds, const Common::Point &destPos,
- int transparentColor = -1) {
- dest->copyFrom(this, srcBounds, destPos, transparentColor);
- }
+ void drawSprite(const Common::Point &pt, SpriteInfo &info, const Common::Rect &clipRect);
/**
* Scroll the screen horizontally by a given amount
@@ -219,14 +146,39 @@ public:
/**
* Create a new surface which is a flipped horizontal copy of the current one
*/
- MSurface *flipHorizontal() const;
+ BaseSurface *flipHorizontal() const;
/**
* Copy an area from one surface to another, translating it using a palette
* map as it's done
*/
- void copyRectTranslate(MSurface &srcSurface, const byte *paletteMap,
+ void copyRectTranslate(BaseSurface &srcSurface, const byte *paletteMap,
const Common::Point &destPos, const Common::Rect &srcRect);
+
+ /**
+ * Copys a sub-section of another surface into the current one.
+ * @param src Source surface
+ * @param destPos Destination position to draw in current surface
+ * @param depth Depth of sprite
+ * @param depthSurface Depth surface to use with sprite depth
+ * @param scale Scale for image
+ * @param flipped Flag for whether image is to be flipped
+ * @param transparentColor Transparency palette index
+ */
+ void copyFrom(BaseSurface &src, const Common::Point &destPos, int depth, DepthSurface *depthSurface,
+ int scale, bool flipped, int transparentColor = -1);
+};
+
+class MSurface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ MSurface() : BaseSurface() {}
+ MSurface(int width, int height) : BaseSurface(width, height) {}
};
class DepthSurface : public MSurface {
@@ -239,7 +191,7 @@ public:
/**
* Constructor
*/
- DepthSurface() : _depthStyle(0) {}
+ DepthSurface() : MSurface(), _depthStyle(0) {}
/**
* Returns the depth at a given position
diff --git a/engines/mads/nebular/dialogs_nebular.cpp b/engines/mads/nebular/dialogs_nebular.cpp
index 58e60fe323..2af80f517e 100644
--- a/engines/mads/nebular/dialogs_nebular.cpp
+++ b/engines/mads/nebular/dialogs_nebular.cpp
@@ -438,11 +438,10 @@ void CopyProtectionDialog::show() {
Common::KeyState curKey;
const Common::Rect inputArea(110, 165, 210, 175);
MSurface *origInput = new MSurface(inputArea.width(), inputArea.height());
- _vm->_screen.frameRect(inputArea, TEXTDIALOG_BLACK);
- _vm->_screen.copyTo(origInput, inputArea, Common::Point(0, 0));
- _font->setColors(TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE);
- _vm->_screen.copyRectToScreen(inputArea);
- _vm->_screen.updateScreen();
+ _vm->_screen->frameRect(inputArea, TEXTDIALOG_BLACK);
+ origInput->blitFrom(*_vm->_screen, inputArea, Common::Point(0, 0));
+ _font->setColors(TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE, TEXTDIALOG_FE);
+ _vm->_screen->update();
bool firstTime = true;
@@ -470,11 +469,10 @@ void CopyProtectionDialog::show() {
_textInput = _hogEntry._word[0];
}
- _vm->_screen.copyFrom(origInput, Common::Rect(0, 0, inputArea.width(), inputArea.height()), Common::Point(inputArea.left, inputArea.top));
- _font->writeString(&_vm->_screen, _textInput,
+ _vm->_screen->blitFrom(*origInput, Common::Point(inputArea.left, inputArea.top));
+ _font->writeString(_vm->_screen, _textInput,
Common::Point(inputArea.left + 2, inputArea.top + 1), 1);
- _vm->_screen.copyRectToScreen(inputArea);
- _vm->_screen.updateScreen();
+ _vm->_screen->update();
}
origInput->free();
@@ -537,7 +535,7 @@ void PictureDialog::save() {
// Save the entire screen
_savedSurface = new MSurface(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
- _vm->_screen.copyTo(_savedSurface);
+ _savedSurface->blitFrom(*_vm->_screen);
// Save palette information
Common::copy(&palette._mainPalette[0], &palette._mainPalette[PALETTE_SIZE], &_palette[0]);
@@ -568,7 +566,7 @@ void PictureDialog::save() {
// Remap the greyed out screen to use the small greyscale range
// at the top end of the palette
- _vm->_screen.translate(map);
+ _vm->_screen->translate(map);
// Load the inventory picture
Common::String setName = Common::String::format("*OB%.3d.SS", _objectId);
@@ -578,13 +576,12 @@ void PictureDialog::save() {
// Get the inventory frame, and adjust the dialog position to allow for it
MSprite *frame = asset->getFrame(0);
_position.y = frame->h + 12;
- if ((_position.y + _height) > _vm->_screen.getHeight())
- _position.y -= (_position.y + _height) - _vm->_screen.getHeight();
+ if ((_position.y + _height) > _vm->_screen->h)
+ _position.y -= (_position.y + _height) - _vm->_screen->h;
// Draw the inventory picture
- frame->copyTo(&_vm->_screen, Common::Point(160 - frame->w / 2, 6),
+ _vm->_screen->transBlitFrom(*frame, Common::Point(160 - frame->w / 2, 6),
frame->getTransparencyIndex());
- _vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
// Adjust the dialog colors to use
TEXTDIALOG_CONTENT1 -= 10;
@@ -598,13 +595,11 @@ void PictureDialog::save() {
void PictureDialog::restore() {
if (_savedSurface) {
- _savedSurface->copyTo(&_vm->_screen);
+ _vm->_screen->blitFrom(*_savedSurface);
_savedSurface->free();
delete _savedSurface;
_savedSurface = nullptr;
- _vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
-
// Restore palette information
Palette &palette = *_vm->_palette;
Common::copy(&_palette[0], &_palette[PALETTE_SIZE], &palette._mainPalette[0]);
@@ -691,7 +686,6 @@ void GameDialog::display() {
}
GameDialog::~GameDialog() {
- _vm->_screen.resetClipBounds();
_vm->_game->_scene._currentSceneId = RETURNING_FROM_DIALOG;
}
diff --git a/engines/mads/nebular/menu_nebular.cpp b/engines/mads/nebular/menu_nebular.cpp
index 0520294b29..cd81efe0f0 100644
--- a/engines/mads/nebular/menu_nebular.cpp
+++ b/engines/mads/nebular/menu_nebular.cpp
@@ -384,8 +384,8 @@ void AdvertView::show() {
// Load the advert background onto the screen
SceneInfo *sceneInfo = SceneInfo::init(_vm);
sceneInfo->load(screenId, 0, Common::String(), 0, _vm->_game->_scene._depthSurface,
- _vm->_screen);
- _vm->_screen.copyRectToScreen(_vm->_screen.getBounds());
+ *_vm->_screen);
+ _vm->_screen->markAllDirty();
_vm->_palette->setFullPalette(_vm->_palette->_mainPalette);
delete sceneInfo;
diff --git a/engines/mads/nebular/nebular_scenes.cpp b/engines/mads/nebular/nebular_scenes.cpp
index da419a70a2..9502d273ea 100644
--- a/engines/mads/nebular/nebular_scenes.cpp
+++ b/engines/mads/nebular/nebular_scenes.cpp
@@ -311,7 +311,7 @@ Common::String NebularScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, int variant) {
File f(Resources::formatName(RESPREFIX_RM, _sceneId, ".DAT"));
MadsPack codesPack(&f);
Common::SeekableReadStream *stream = codesPack.getItemStream(variant + 1);
@@ -322,9 +322,9 @@ void SceneInfoNebular::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoNebular::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
- byte *destP = depthSurface.getData();
- byte *endP = depthSurface.getBasePtr(0, depthSurface.h);
+void SceneInfoNebular::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
+ byte *destP = (byte *)depthSurface.getPixels();
+ byte *endP = (byte *)depthSurface.getBasePtr(0, depthSurface.h);
byte runLength = stream->readByte();
while (destP < endP && runLength > 0) {
diff --git a/engines/mads/nebular/nebular_scenes.h b/engines/mads/nebular/nebular_scenes.h
index 58a6d1c98f..b600c6dbe1 100644
--- a/engines/mads/nebular/nebular_scenes.h
+++ b/engines/mads/nebular/nebular_scenes.h
@@ -1373,9 +1373,9 @@ public:
class SceneInfoNebular : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/nebular/nebular_scenes2.cpp b/engines/mads/nebular/nebular_scenes2.cpp
index 5210f59f47..c19b7b8381 100644
--- a/engines/mads/nebular/nebular_scenes2.cpp
+++ b/engines/mads/nebular/nebular_scenes2.cpp
@@ -103,7 +103,7 @@ void Scene2xx::sceneEntrySound() {
_vm->_sound->command(1);
else
_vm->_sound->command(9);
- break;
+ break;
case 216:
_vm->_sound->command(16);
break;
diff --git a/engines/mads/nebular/nebular_scenes3.cpp b/engines/mads/nebular/nebular_scenes3.cpp
index 0fb13a706c..7323ee893d 100644
--- a/engines/mads/nebular/nebular_scenes3.cpp
+++ b/engines/mads/nebular/nebular_scenes3.cpp
@@ -2818,7 +2818,7 @@ void Scene318::step() {
if (_internCounter >= 3600) {
_vm->_sound->command(59);
- _vm->_screen._shakeCountdown = 20;
+ _vm->_screen->_shakeCountdown = 20;
_internWalkingFl = true;
}
}
@@ -3288,22 +3288,22 @@ void Scene319::step() {
if (_animMode == 2) {
if (_animFrame == 13)
- _vm->_screen._shakeCountdown = 40;
+ _vm->_screen->_shakeCountdown = 40;
if (_animFrame == 16)
- _vm->_screen._shakeCountdown = 1;
+ _vm->_screen->_shakeCountdown = 1;
}
if (_animMode == 3) {
if (_animFrame == 11)
- _vm->_screen._shakeCountdown = 60;
+ _vm->_screen->_shakeCountdown = 60;
if (_animFrame == 18)
- _vm->_screen._shakeCountdown = 1;
+ _vm->_screen->_shakeCountdown = 1;
}
if ((_animMode == 4) && (_animFrame == 16))
- _vm->_screen._shakeCountdown = 80;
+ _vm->_screen->_shakeCountdown = 80;
if ((nextFrame >= 0) && (nextFrame != _scene->_animation[0]->getCurrentFrame())) {
_scene->_animation[0]->setCurrentFrame(nextFrame);
@@ -3326,7 +3326,7 @@ void Scene319::step() {
_animFrame = _scene->_animation[0]->getCurrentFrame();
_slacheTalkingFl = true;
- _vm->_screen._shakeCountdown = 1;
+ _vm->_screen->_shakeCountdown = 1;
for (int i = 0; i <= 1; i++) {
int oldIdx = _globals._sequenceIndexes[i];
@@ -3350,7 +3350,7 @@ void Scene319::step() {
_vm->_palette->setColorValues(0, 0, 0);
_vm->_palette->fadeOut(_vm->_palette->_mainPalette, nullptr, 18, 228,
248, 0, 1, 16);
- _vm->_screen._shakeCountdown = 1;
+ _vm->_screen->_shakeCountdown = 1;
_scene->_reloadSceneFlag = true;
break;
@@ -3731,7 +3731,7 @@ void Scene320::step() {
case 417:
case 457:
- _vm->_screen._shakeCountdown = 40;
+ _vm->_screen->_shakeCountdown = 40;
_vm->_sound->command(59);
break;
diff --git a/engines/mads/nebular/sound_nebular.cpp b/engines/mads/nebular/sound_nebular.cpp
index 4c360b23d5..5f71c99a94 100644
--- a/engines/mads/nebular/sound_nebular.cpp
+++ b/engines/mads/nebular/sound_nebular.cpp
@@ -20,16 +20,15 @@
*
*/
-#include "audio/audiostream.h"
#include "audio/fmopl.h"
-#include "audio/decoders/raw.h"
#include "common/algorithm.h"
-#include "common/debug.h"
#include "common/md5.h"
-#include "common/memstream.h"
-#include "mads/sound.h"
#include "mads/nebular/sound_nebular.h"
+namespace Audio {
+class Mixer;
+}
+
namespace MADS {
namespace Nebular {
diff --git a/engines/mads/nebular/sound_nebular.h b/engines/mads/nebular/sound_nebular.h
index 2b80b08d89..a9e1493109 100644
--- a/engines/mads/nebular/sound_nebular.h
+++ b/engines/mads/nebular/sound_nebular.h
@@ -27,8 +27,14 @@
#include "common/file.h"
#include "common/mutex.h"
#include "common/queue.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
+
+namespace Audio {
+class Mixer;
+}
+
+namespace Common {
+class SeekableReadStream;
+}
namespace OPL {
class OPL;
@@ -36,8 +42,6 @@ class OPL;
namespace MADS {
-class SoundManager;
-
namespace Nebular {
class ASound;
diff --git a/engines/mads/phantom/phantom_scenes.cpp b/engines/mads/phantom/phantom_scenes.cpp
index f7a7153fbe..bfb521e369 100644
--- a/engines/mads/phantom/phantom_scenes.cpp
+++ b/engines/mads/phantom/phantom_scenes.cpp
@@ -174,7 +174,7 @@ Common::String PhantomScene::formAnimName(char sepChar, int suffixNum) {
/*------------------------------------------------------------------------*/
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
+void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, int variant) {
Common::String ext = Common::String::format(".WW%d", variant);
Common::String fileName = Resources::formatName(RESPREFIX_RM, _sceneId, ext);
if (!Common::File::exists(fileName))
@@ -190,8 +190,8 @@ void SceneInfoPhantom::loadCodes(MSurface &depthSurface, int variant) {
f.close();
}
-void SceneInfoPhantom::loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) {
- byte *destP = depthSurface.getData();
+void SceneInfoPhantom::loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) {
+ byte *destP = (byte *)depthSurface.getPixels();
byte *walkMap = new byte[stream->size()];
stream->read(walkMap, stream->size());
diff --git a/engines/mads/phantom/phantom_scenes.h b/engines/mads/phantom/phantom_scenes.h
index a6a8395a2c..6b7ab697f3 100644
--- a/engines/mads/phantom/phantom_scenes.h
+++ b/engines/mads/phantom/phantom_scenes.h
@@ -474,9 +474,9 @@ public:
class SceneInfoPhantom : public SceneInfo {
friend class SceneInfo;
protected:
- virtual void loadCodes(MSurface &depthSurface, int variant);
+ virtual void loadCodes(BaseSurface &depthSurface, int variant);
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream);
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream);
/**
* Constructor
diff --git a/engines/mads/rails.cpp b/engines/mads/rails.cpp
index ee0ca98cd3..46d9e0ebd3 100644
--- a/engines/mads/rails.cpp
+++ b/engines/mads/rails.cpp
@@ -149,7 +149,7 @@ int Rails::scanPath(const Common::Point &srcPos, const Common::Point &destPos) {
++xDiff;
++yDiff;
- const byte *srcP = _depthSurface->getBasePtr(srcPos.x, srcPos.y);
+ const byte *srcP = (const byte *)_depthSurface->getBasePtr(srcPos.x, srcPos.y);
int index = xAmount;
// Outer loop
diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp
index 83ab1151a9..66f56f9407 100644
--- a/engines/mads/scene.cpp
+++ b/engines/mads/scene.cpp
@@ -89,8 +89,7 @@ Scene::~Scene() {
}
void Scene::restrictScene() {
- _sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
- _vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
+ _sceneSurface.create(*_vm->_screen, Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT));
}
void Scene::clearVocab() {
@@ -517,7 +516,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
if (_posAdjust != Common::Point(0, 0))
warning("Adjust used %d %d", _posAdjust.x, _posAdjust.y);
// Copy background for the dirty areas to the screen
- _dirtyAreas.copy(&_backgroundSurface, &_vm->_screen, _posAdjust);
+ _dirtyAreas.copy(&_backgroundSurface, _vm->_screen, _posAdjust);
// Handle dirty areas for foreground objects
_spriteSlots.setDirtyAreas();
@@ -528,11 +527,11 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
_spriteSlots.drawSprites(&_sceneSurface);
// Draw text elements onto the view
- _textDisplay.draw(&_vm->_screen);
+ _textDisplay.draw(_vm->_screen);
if (transitionType) {
// Fading in the screen
- _vm->_screen.transition(transitionType, surfaceFlag);
+ _vm->_screen->transition(transitionType, surfaceFlag);
_vm->_sound->startQueuedCommands();
} else {
// Copy dirty areas to the screen
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index 7b0e64c1fe..21fd4f9026 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -128,7 +128,7 @@ SceneInfo *SceneInfo::init(MADSEngine *vm) {
}
void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
- int flags, DepthSurface &depthSurface, MSurface &bgSurface) {
+ int flags, DepthSurface &depthSurface, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
// Figure out the resource to use
@@ -242,13 +242,13 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
int height = _height;
if (!bgSurface.getPixels() || (bgSurface.w != width) || (bgSurface.h != height)) {
- bgSurface.setSize(width, height);
+ bgSurface.create(width, height);
}
if (_depthStyle == 2)
width >>= 2;
if (!depthSurface.getPixels()) {
- depthSurface.setSize(width, height);
+ depthSurface.create(width, height);
}
loadCodes(depthSurface, variant);
@@ -288,7 +288,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
assert(asset && _depthStyle != 2);
MSprite *spr = asset->getFrame(si._frameNumber);
- bgSurface.copyFrom(spr, si._position, si._depth, &depthSurface,
+ bgSurface.copyFrom(*spr, si._position, si._depth, &depthSurface,
si._scale, false, spr->getTransparencyIndex());
}
@@ -299,7 +299,7 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
}
}
-void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
Common::String resourceName;
bool isV2 = (_vm->getGameID() != GType_RexNebular);
@@ -351,7 +351,7 @@ void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &r
}
}
-void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface) {
bool sceneFlag = sceneId >= 0;
Common::String resourceName;
Common::SeekableReadStream *stream;
@@ -397,7 +397,7 @@ void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName,
artFile.close();
}
-void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface) {
Common::String tileMapResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".MM");
File tileMapFile(tileMapResourceName);
MadsPack tileMapPack(&tileMapFile);
@@ -455,7 +455,7 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName,
newHeight = tileCount * tileHeight;
if (bgSurface.w != newWidth || bgSurface.h != newHeight)
- bgSurface.setSize(newWidth, newHeight);
+ bgSurface.create(newWidth, newHeight);
// --------------------------------------------------------------------------------
@@ -477,7 +477,7 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName,
//debugCN(kDebugGraphics, "Tile: %i, compressed size: %i\n", i, compressedTileDataSize);
- newTile->empty();
+ newTile->clear();
byte *compressedTileData = new byte[compressedTileDataSize];
@@ -503,7 +503,8 @@ void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName,
TileSetIterator tile = tileSet.begin();
for (int i = 0; i < tileIndex; i++)
++tile;
- ((*tile).get())->copyTo(&bgSurface, Common::Point(x * tileWidth, y * tileHeight));
+
+ bgSurface.blitFrom(*(*tile).get(), Common::Point(x * tileWidth, y * tileHeight));
((*tile).get())->free();
}
}
diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h
index 41a08f74eb..a28c42c5ab 100644
--- a/engines/mads/scene_data.h
+++ b/engines/mads/scene_data.h
@@ -189,36 +189,36 @@ public:
* loads the data
*/
void load(int sceneId, int variant, const Common::String &resName, int flags,
- DepthSurface &depthSurface, MSurface &bgSurface);
+ DepthSurface &depthSurface, BaseSurface &bgSurface);
/**
* Loads the palette for a scene
*/
- void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads a V1 game background
*/
- void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadMadsV1Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads a V2 game background
*/
- void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface);
+ void loadMadsV2Background(int sceneId, const Common::String &resName, int flags, BaseSurface &bgSurface);
/**
* Loads the given surface with depth information of a given scene
* @param depthSurface Depth/walk surface
* @param variant Variant number to load
*/
- virtual void loadCodes(MSurface &depthSurface, int variant) = 0;
+ virtual void loadCodes(BaseSurface &depthSurface, int variant) = 0;
/**
* Loads the given surface with depth information of a given scene
* @param depthSurface Depth/walk surface
* @param stream Stream to load the data from
*/
- virtual void loadCodes(MSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
+ virtual void loadCodes(BaseSurface &depthSurface, Common::SeekableReadStream *stream) = 0;
};
} // End of namespace MADS
diff --git a/engines/mads/screen.cpp b/engines/mads/screen.cpp
index 90fbbe7e2a..b17b6e93b8 100644
--- a/engines/mads/screen.cpp
+++ b/engines/mads/screen.cpp
@@ -69,7 +69,6 @@ void DirtyArea::setArea(int width, int height, int maxWidth, int maxHeight) {
_active = true;
}
-
void DirtyArea::setSpriteSlot(const SpriteSlot *spriteSlot) {
int width, height;
Scene &scene = _vm->_game->_scene;
@@ -202,7 +201,7 @@ void DirtyAreas::mergeAreas(int idx1, int idx2) {
da1._textActive = true;
}
-void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust) {
+void DirtyAreas::copy(BaseSurface *srcSurface, BaseSurface *destSurface, const Common::Point &posAdjust) {
for (uint i = 0; i < size(); ++i) {
const Common::Rect &srcBounds = (*this)[i]._bounds;
@@ -215,12 +214,13 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common:
Common::Point destPos(srcBounds.left, srcBounds.top);
if ((*this)[i]._active && bounds.isValidRect()) {
- srcSurface->copyTo(destSurface, bounds, destPos);
+ destSurface->blitFrom(*srcSurface, bounds, destPos);
}
}
}
void DirtyAreas::copyToScreen() {
+/*
for (uint i = 0; i < size(); ++i) {
const Common::Rect &bounds = (*this)[i]._bounds;
@@ -229,9 +229,10 @@ void DirtyAreas::copyToScreen() {
continue;
if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) {
- _vm->_screen.copyRectToScreen(bounds);
+ _vm->_screen->copyRectToScreen(bounds);
}
}
+ */
}
void DirtyAreas::reset() {
@@ -554,38 +555,17 @@ void ScreenObjects::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-ScreenSurface::ScreenSurface() {
+Screen::Screen(): BaseSurface() {
+ // Create the screen surface separately on another surface, since the screen
+ // surface will be subject to change as the clipping area is altered
+ _rawSurface.create(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
+ resetClipBounds();
+
_shakeCountdown = -1;
_random = 0x4D2;
- _surfacePixels = nullptr;
-}
-
-void ScreenSurface::init() {
- // Set the size for the screen
- setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
-
- // Store a copy of the raw pixels pointer for the screen, since the surface
- // itself may be later changed to only a subset of the screen
- _surfacePixels = (byte *)getPixels();
- _freeFlag = false;
-}
-
-ScreenSurface::~ScreenSurface() {
- ::free(_surfacePixels);
}
-void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) {
- const byte *buf = getBasePtr(bounds.left, bounds.top);
-
- Common::Rect destBounds = bounds;
- destBounds.translate(_clipBounds.left, _clipBounds.top);
-
- if (bounds.width() != 0 && bounds.height() != 0)
- g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top,
- destBounds.width(), destBounds.height());
-}
-
-void ScreenSurface::updateScreen() {
+void Screen::update() {
if (_shakeCountdown >= 0) {
_random = _random * 5 + 1;
int offset = (_random >> 8) & 3;
@@ -596,27 +576,42 @@ void ScreenSurface::updateScreen() {
// offset width shown at the very right. The offset changes to give
// an effect of shaking the screen
offset *= 4;
- const byte *buf = getBasePtr(offset, 0);
- g_system->copyRectToScreen(buf, this->pitch, 0, 0,
- this->pitch - offset, this->h);
+ const byte *buf = (const byte *)getBasePtr(offset, 0);
+ g_system->copyRectToScreen(buf, this->pitch, 0, 0, this->pitch - offset, this->h);
if (offset > 0)
- g_system->copyRectToScreen(this->pixels, this->pitch,
+ g_system->copyRectToScreen(getPixels(), this->pitch,
this->pitch - offset, 0, offset, this->h);
+ return;
}
- g_system->updateScreen();
+ // Reset any clip bounds if active whilst the screen is updated
+ Common::Rect clipBounds = getClipBounds();
+ resetClipBounds();
+
+ // Update the screen
+ Graphics::Screen::update();
+
+ // Revert back to whatever clipping is active
+ setClipBounds(clipBounds);
}
-void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag) {
+void Screen::transition(ScreenTransition transitionType, bool surfaceFlag) {
Palette &pal = *_vm->_palette;
Scene &scene = _vm->_game->_scene;
byte palData[PALETTE_SIZE];
+ // The original loads the new scene to the screen surface for some of the
+ // transition types like fade out/in, so we need to clear the dirty rects so
+ // it doesn't prematurely get blitted to the physical screen before fade out
+ Common::Rect clipBounds = getClipBounds();
+ clearDirtyRects();
+
switch (transitionType) {
case kTransitionFadeIn:
- case kTransitionFadeOutIn:
+ case kTransitionFadeOutIn: {
Common::fill(&pal._colorValues[0], &pal._colorValues[3], 0);
Common::fill(&pal._colorFlags[0], &pal._colorFlags[3], false);
+ resetClipBounds();
if (transitionType == kTransitionFadeOutIn) {
// Fade out
@@ -628,9 +623,11 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag
Common::fill(&palData[0], &palData[PALETTE_SIZE], 0);
pal.setFullPalette(palData);
- copyRectToScreen(getBounds());
+ markAllDirty();
+ update();
pal.fadeIn(palData, pal._mainPalette, 0, 256, 0, 1, 1, 16);
break;
+ }
case kTransitionBoxInBottomLeft:
case kTransitionBoxInBottomRight:
@@ -666,19 +663,13 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag
// Quick transitions
break;
}
-}
-void ScreenSurface::setClipBounds(const Common::Rect &r) {
- _clipBounds = r;
- setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height());
- this->pitch = MADS_SCREEN_WIDTH;
+ // Reset clipping
+ markAllDirty();
+ setClipBounds(clipBounds);
}
-void ScreenSurface::resetClipBounds() {
- setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
-}
-
-void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entrySide,
+void Screen::panTransition(MSurface &newScreen, byte *palData, int entrySide,
const Common::Point &srcPos, const Common::Point &destPos,
ThroughBlack throughBlack, bool setPalette, int numTicks) {
EventsManager &events = *_vm->_events;
@@ -735,8 +726,6 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS
srcPos.x + xAt + 1, srcPos.y + size.y));
}
- copyRectToScreen(Common::Rect(xAt, destPos.y, xAt + 1, destPos.y + size.y));
-
// Slight delay
events.pollEvents();
g_system->delayMillis(1);
@@ -747,16 +736,18 @@ void ScreenSurface::panTransition(MSurface &newScreen, byte *palData, int entryS
}
if (throughBlack == THROUGH_BLACK2) {
+ /*
Common::Rect r(srcPos.x, srcPos.y, srcPos.x + size.x, srcPos.y + size.y);
copyRectToSurface(newScreen, destPos.x, destPos.y, r);
copyRectToScreen(r);
+ */
}
}
/**
* Translates the current screen from the old palette to the new palette
*/
-void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteMap) {
+void Screen::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteMap) {
Palette &palette = *_vm->_palette;
byte oldPalette[PALETTE_SIZE];
byte oldMap[PALETTE_COUNT];
@@ -775,7 +766,7 @@ void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteM
destP += 2 * RGB_SIZE;
}
- Common::Rect oldClip = _clipBounds;
+ Common::Rect oldClip = getClipBounds();
resetClipBounds();
copyRectTranslate(*this, oldMap, Common::Point(0, 0),
@@ -790,7 +781,7 @@ void ScreenSurface::swapForeground(byte newPalette[PALETTE_SIZE], byte *paletteM
* Palettes consist of 128 RGB entries for the foreground and background
* respectively, with the two interleaved together. So the start
*/
-void ScreenSurface::swapPalette(const byte *palData, byte swapTable[PALETTE_COUNT],
+void Screen::swapPalette(const byte *palData, byte swapTable[PALETTE_COUNT],
bool foreground) {
int start = foreground ? 1 : 0;
const byte *dynamicList = &palData[start * RGB_SIZE];
@@ -815,5 +806,12 @@ void ScreenSurface::swapPalette(const byte *palData, byte swapTable[PALETTE_COUN
}
}
+void Screen::setClipBounds(const Common::Rect &r) {
+ create(_rawSurface, r);
+}
+
+void Screen::resetClipBounds() {
+ setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
+}
} // End of namespace MADS
diff --git a/engines/mads/screen.h b/engines/mads/screen.h
index d910e88633..eeb15453f8 100644
--- a/engines/mads/screen.h
+++ b/engines/mads/screen.h
@@ -117,7 +117,7 @@ public:
* @param destSurface Dest surface
* @param posAdjust Position adjustment
*/
- void copy(MSurface *srcSurface, MSurface *destSurface, const Common::Point &posAdjust);
+ void copy(BaseSurface *srcSurface, BaseSurface *destSurface, const Common::Point &posAdjust);
/**
* Use the lsit of dirty areas to copy areas of the screen surface to
@@ -128,7 +128,6 @@ public:
void reset();
};
-
class ScreenObject {
public:
bool _active;
@@ -207,11 +206,10 @@ public:
void synchronize(Common::Serializer &s);
};
-class ScreenSurface : public MSurface {
+class Screen : public BaseSurface {
private:
uint16 _random;
- byte *_surfacePixels;
- Common::Rect _clipBounds;
+ MSurface _rawSurface;
void panTransition(MSurface &newScreen, byte *palData, int entrySide,
const Common::Point &srcPos, const Common::Point &destPos,
@@ -226,36 +224,40 @@ public:
/**
* Constructor
*/
- ScreenSurface();
+ Screen();
/**
* Destructor
*/
- ~ScreenSurface();
+ virtual ~Screen() {}
/**
- * Initialize the surface
+ * Updates the physical screen with contents of the internal surface
*/
- void init();
+ virtual void update();
/**
- * Copys an area of the screen surface to the ScmmVM physical screen buffer
- * @param bounds Area of screen surface to copy
+ * Transition to a new screen with a given effect
*/
- void copyRectToScreen(const Common::Rect &bounds);
+ void transition(ScreenTransition transitionType, bool surfaceFlag);
/**
- * Updates the screen with the contents of the surface
+ * Set the screen drawing area to a sub-section of the real screen
*/
- void updateScreen();
-
- void transition(ScreenTransition transitionType, bool surfaceFlag);
-
void setClipBounds(const Common::Rect &r);
+ /**
+ * Reset back to drawing on the entirety of the screen
+ */
void resetClipBounds();
- const Common::Rect &getClipBounds() { return _clipBounds; }
+ /**
+ * Return the current drawing/clip area
+ */
+ const Common::Rect getClipBounds() const {
+ const Common::Point pt = getOffsetFromOwner();
+ return Common::Rect(pt.x, pt.y, pt.x + this->w, pt.y + this->h);
+ }
};
} // End of namespace MADS
diff --git a/engines/mads/sequence.cpp b/engines/mads/sequence.cpp
index 50b37de7ea..2afe089d4a 100644
--- a/engines/mads/sequence.cpp
+++ b/engines/mads/sequence.cpp
@@ -237,8 +237,8 @@ bool SequenceList::loadSprites(int seqIndex) {
if ((seqEntry._flags != 0) || (seqEntry._dynamicHotspotIndex >= 0)) {
SpriteAsset &spriteSet = *scene._sprites[seqEntry._spritesIndex];
MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1);
- int width = frame->getWidth() * seqEntry._scale / 200;
- int height = frame->getHeight() * seqEntry._scale / 100;
+ int width = frame->w * seqEntry._scale / 200;
+ int height = frame->h * seqEntry._scale / 100;
Common::Point pt = spriteSlot._position;
// Handle sprite movement, if present
diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp
index c96fd01882..5f2c9aca56 100644
--- a/engines/mads/sound.cpp
+++ b/engines/mads/sound.cpp
@@ -20,14 +20,16 @@
*
*/
-#include "audio/audiostream.h"
#include "audio/fmopl.h"
-#include "audio/decoders/raw.h"
#include "common/memstream.h"
#include "mads/sound.h"
#include "mads/mads.h"
#include "mads/nebular/sound_nebular.h"
+namespace Audio {
+class Mixer;
+}
+
namespace MADS {
SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) {
diff --git a/engines/mads/sound.h b/engines/mads/sound.h
index 2c4de6f21d..9674d4198d 100644
--- a/engines/mads/sound.h
+++ b/engines/mads/sound.h
@@ -25,12 +25,21 @@
#include "common/scummsys.h"
#include "common/queue.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
-#include "mads/nebular/sound_nebular.h"
+
+namespace Audio {
+class Mixer;
+}
+
+namespace OPL {
+class OPL;
+}
namespace MADS {
+namespace Nebular {
+class ASound;
+}
+
class MADSEngine;
class SoundManager {
diff --git a/engines/mads/sprites.cpp b/engines/mads/sprites.cpp
index 0a1c0b710d..84060ccdfe 100644
--- a/engines/mads/sprites.cpp
+++ b/engines/mads/sprites.cpp
@@ -59,10 +59,10 @@ MSprite::MSprite() : MSurface() {
}
MSprite::MSprite(Common::SeekableReadStream *source, const Common::Array<RGB6> &palette,
- const Common::Rect &bounds)
- : MSurface(bounds.width(), bounds.height()),
- _offset(Common::Point(bounds.left, bounds.top)), _transparencyIndex(TRANSPARENT_COLOR_INDEX) {
+ const Common::Rect &bounds): MSurface(), _transparencyIndex(TRANSPARENT_COLOR_INDEX),
+ _offset(Common::Point(bounds.left, bounds.top)) {
// Load the sprite data
+ create(bounds.width(), bounds.height());
loadSprite(source, palette);
}
@@ -74,8 +74,8 @@ void MSprite::loadSprite(Common::SeekableReadStream *source,
byte *outp, *lineStart;
bool newLine = false;
- outp = getData();
- lineStart = getData();
+ outp = getPixels();
+ lineStart = getPixels();
int spriteSize = this->w * this->h;
byte transIndex = getTransparencyIndex();
Common::fill(outp, outp + spriteSize, transIndex);
@@ -84,7 +84,7 @@ void MSprite::loadSprite(Common::SeekableReadStream *source,
byte cmd1, cmd2, count, pixel;
if (newLine) {
- outp = lineStart + getWidth();
+ outp = lineStart + this->w;
lineStart = outp;
newLine = false;
}
@@ -126,7 +126,7 @@ void MSprite::loadSprite(Common::SeekableReadStream *source,
// Do a final iteration over the sprite to convert it's pixels to
// the final positions in the main palette
spriteSize = this->w * this->h;
- for (outp = getData(); spriteSize > 0; --spriteSize, ++outp) {
+ for (outp = getPixels(); spriteSize > 0; --spriteSize, ++outp) {
if (*outp != transIndex)
*outp = palette[*outp]._palIndex;
}
@@ -257,12 +257,12 @@ void SpriteSlots::drawBackground() {
}
if (spriteSlot._depth <= 1) {
- frame->copyTo(&scene._backgroundSurface, pt, frame->getTransparencyIndex());
+ scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex());
} else if (scene._depthStyle == 0) {
- scene._backgroundSurface.copyFrom(frame, pt, spriteSlot._depth, &scene._depthSurface,
+ scene._backgroundSurface.copyFrom(*frame, pt, spriteSlot._depth, &scene._depthSurface,
-1, false, frame->getTransparencyIndex());
} else {
- frame->copyTo(&scene._backgroundSurface, pt, frame->getTransparencyIndex());
+ scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex());
}
}
}
@@ -319,7 +319,7 @@ void SpriteSlots::drawSprites(MSurface *s) {
if ((slot._scale < 100) && (slot._scale != -1)) {
// Scaled drawing
- s->copyFrom(sprite, slot._position, slot._depth, &scene._depthSurface,
+ s->copyFrom(*sprite, slot._position, slot._depth, &scene._depthSurface,
slot._scale, flipped, sprite->getTransparencyIndex());
} else {
int xp, yp;
@@ -334,17 +334,17 @@ void SpriteSlots::drawSprites(MSurface *s) {
if (slot._depth > 1) {
// Draw the frame with depth processing
- s->copyFrom(sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface,
+ s->copyFrom(*sprite, Common::Point(xp, yp), slot._depth, &scene._depthSurface,
-1, flipped, sprite->getTransparencyIndex());
} else {
- MSurface *spr = sprite;
+ BaseSurface *spr = sprite;
if (flipped) {
// Create a flipped copy of the sprite temporarily
spr = sprite->flipHorizontal();
}
// No depth, so simply draw the image
- spr->copyTo(s, Common::Point(xp, yp), sprite->getTransparencyIndex());
+ s->transBlitFrom(*spr, Common::Point(xp, yp), sprite->getTransparencyIndex());
// Free sprite if it was a flipped one
if (flipped) {
diff --git a/engines/mads/user_interface.cpp b/engines/mads/user_interface.cpp
index e4b09ff54c..204f71fe43 100644
--- a/engines/mads/user_interface.cpp
+++ b/engines/mads/user_interface.cpp
@@ -112,7 +112,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) {
Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
} else {
// Copy area
- userInterface._surface.copyTo(&userInterface, dirtyArea._bounds,
+ userInterface.blitFrom(userInterface._surface, dirtyArea._bounds,
Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
}
}
@@ -155,13 +155,13 @@ void UISlots::draw(bool updateFlag, bool delFlag) {
if (slot._segmentId == IMG_SPINNING_OBJECT) {
MSprite *sprite = asset->getFrame(frameNumber - 1);
- sprite->copyTo(&userInterface, slot._position,
+ userInterface.transBlitFrom(*sprite, slot._position,
sprite->getTransparencyIndex());
} else {
MSprite *sprite = asset->getFrame(frameNumber - 1);
if (flipped) {
- MSurface *spr = sprite->flipHorizontal();
+ BaseSurface *spr = sprite->flipHorizontal();
userInterface.mergeFrom(spr, spr->getBounds(), slot._position,
sprite->getTransparencyIndex());
spr->free();
@@ -185,7 +185,7 @@ void UISlots::draw(bool updateFlag, bool delFlag) {
// Flag area of screen as needing update
Common::Rect r = dirtyArea._bounds;
r.translate(0, scene._interfaceY);
- _vm->_screen.copyRectToScreen(r);
+ //_vm->_screen->copyRectToScreen(r);
}
}
}
@@ -339,10 +339,10 @@ UserInterface::UserInterface(MADSEngine *vm) : _vm(vm), _dirtyAreas(vm),
Common::fill(&_categoryIndexes[0], &_categoryIndexes[7], 0);
// Map the user interface to the bottom of the game's screen surface
- byte *pData = _vm->_screen.getBasePtr(0, MADS_SCENE_HEIGHT);
- setPixels(pData, MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
+ create(*_vm->_screen, Common::Rect(0, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
+ MADS_SCREEN_HEIGHT));
- _surface.setSize(MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
+ _surface.create(MADS_SCREEN_WIDTH, MADS_INTERFACE_HEIGHT);
}
void UserInterface::load(const Common::String &resName) {
@@ -367,7 +367,7 @@ void UserInterface::load(const Common::String &resName) {
// Read in the surface data
Common::SeekableReadStream *pixelsStream = madsPack.getItemStream(1);
- pixelsStream->read(_surface.getData(), MADS_SCREEN_WIDTH * MADS_INTERFACE_HEIGHT);
+ pixelsStream->read(_surface.getPixels(), MADS_SCREEN_WIDTH * MADS_INTERFACE_HEIGHT);
delete pixelsStream;
}
@@ -390,7 +390,7 @@ void UserInterface::setup(InputMode inputMode) {
resName += ".INT";
load(resName);
- _surface.copyTo(this);
+ blitFrom(_surface);
}
_vm->_game->_screenObjects._inputMode = inputMode;
@@ -429,7 +429,7 @@ void UserInterface::drawTextElements() {
}
}
-void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds,
+void UserInterface::mergeFrom(BaseSurface *src, const Common::Rect &srcBounds,
const Common::Point &destPos, int transparencyIndex) {
// Validation of the rectangle and position
int destX = destPos.x, destY = destPos.y;
@@ -455,9 +455,9 @@ void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds,
// Copy the specified area
- byte *data = src->getData();
- byte *srcPtr = data + (src->getWidth() * copyRect.top + copyRect.left);
- byte *destPtr = (byte *)this->pixels + (destY * getWidth()) + destX;
+ byte *data = src->getPixels();
+ byte *srcPtr = data + (src->w * copyRect.top + copyRect.left);
+ byte *destPtr = (byte *)getPixels() + (destY * this->w) + destX;
for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) {
// Process each line of the area
@@ -468,8 +468,8 @@ void UserInterface::mergeFrom(MSurface *src, const Common::Rect &srcBounds,
destPtr[xCtr] = srcPtr[xCtr];
}
- srcPtr += src->getWidth();
- destPtr += getWidth();
+ srcPtr += src->w;
+ destPtr += this->w;
}
}
@@ -593,7 +593,7 @@ void UserInterface::scrollbarChanged() {
_uiSlots.add(r);
_uiSlots.draw(false, false);
drawScroller();
- updateRect(r);
+// updateRect(r);
}
void UserInterface::writeVocab(ScrCategory category, int id) {
@@ -1012,7 +1012,7 @@ void UserInterface::selectObject(int invIndex) {
_uiSlots.add(bounds);
_uiSlots.draw(false, false);
drawItemVocabList();
- updateRect(bounds);
+ //updateRect(bounds);
}
}
@@ -1036,7 +1036,7 @@ void UserInterface::updateSelection(ScrCategory category, int newIndex, int *idx
_uiSlots.add(bounds);
_uiSlots.draw(false, false);
drawInventoryList();
- updateRect(bounds);
+ //updateRect(bounds);
_inventoryChanged = false;
if (invList.size() < 2) {
@@ -1052,25 +1052,19 @@ void UserInterface::updateSelection(ScrCategory category, int newIndex, int *idx
if (oldIndex >= 0) {
writeVocab(category, oldIndex);
- if (getBounds(category, oldIndex, bounds))
- updateRect(bounds);
+/* if (getBounds(category, oldIndex, bounds))
+ updateRect(bounds); */
}
if (newIndex >= 0) {
writeVocab(category, newIndex);
- if (getBounds(category, newIndex, bounds))
- updateRect(bounds);
+/* if (getBounds(category, newIndex, bounds))
+ updateRect(bounds); */
}
}
}
-void UserInterface::updateRect(const Common::Rect &bounds) {
- Common::Rect r = bounds;
- r.translate(0, MADS_SCENE_HEIGHT);
- _vm->_screen.copyRectToScreen(r);
-}
-
void UserInterface::scrollerChanged() {
warning("TODO: scrollerChanged");
}
diff --git a/engines/mads/user_interface.h b/engines/mads/user_interface.h
index 60cc1f736d..6c9485998a 100644
--- a/engines/mads/user_interface.h
+++ b/engines/mads/user_interface.h
@@ -190,8 +190,6 @@ private:
* Draw a UI textual element
*/
void writeVocab(ScrCategory category, int id);
-
- void updateRect(const Common::Rect &bounds);
public:
MSurface _surface;
UISlots _uiSlots;
@@ -240,7 +238,7 @@ public:
* @param destPos Destination position to draw in current surface
* @param transparencyIndex Transparency color
*/
- void mergeFrom(MSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
+ void mergeFrom(BaseSurface *src, const Common::Rect &srcBounds, const Common::Point &destPos,
int transparencyIndex = -1);
/**
diff --git a/engines/mohawk/POTFILES b/engines/mohawk/POTFILES
index 54d9dcaa3a..036059da6a 100644
--- a/engines/mohawk/POTFILES
+++ b/engines/mohawk/POTFILES
@@ -1,3 +1,4 @@
+engines/mohawk/detection.cpp
engines/mohawk/dialogs.cpp
engines/mohawk/myst.cpp
engines/mohawk/riven.cpp
diff --git a/engines/mohawk/bitmap.cpp b/engines/mohawk/bitmap.cpp
index 6435daf46f..d8c6d6aacd 100644
--- a/engines/mohawk/bitmap.cpp
+++ b/engines/mohawk/bitmap.cpp
@@ -53,6 +53,16 @@ MohawkBitmap::MohawkBitmap() {
_drawTable = drawTable;
_drawTableSize = ARRAYSIZE(drawTable);
+
+ _header.width = 0;
+ _header.height = 0;
+ _header.bytesPerRow = 0;
+ _header.format = 0;
+ _header.colorTable.colorCount = 0;
+ _header.colorTable.palette = nullptr;
+ _header.colorTable.rgbBits = 0;
+ _header.colorTable.tableSize = 0;
+ _data = nullptr;
}
MohawkBitmap::~MohawkBitmap() {
diff --git a/engines/mohawk/configure.engine b/engines/mohawk/configure.engine
index 47402c4560..ccb9499ef0 100644
--- a/engines/mohawk/configure.engine
+++ b/engines/mohawk/configure.engine
@@ -1,6 +1,6 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books"
+add_engine mohawk "Mohawk" yes "cstime myst riven" "Living Books" "highres"
add_engine cstime "Where in Time is Carmen Sandiego?" no
add_engine riven "Riven: The Sequel to Myst" no "" "" "16bit"
-add_engine myst "Myst" no
+add_engine myst "Myst" yes
diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h
index f95222d3a1..bfb7daf945 100644
--- a/engines/mohawk/cstime.h
+++ b/engines/mohawk/cstime.h
@@ -111,7 +111,7 @@ enum {
};
struct CSTimeEvent {
- CSTimeEvent() { }
+ CSTimeEvent() : type(0), param1(0), param2(0) { }
CSTimeEvent(uint16 t, uint16 p1, uint16 p2) : type(t), param1(p1), param2(p2) { }
uint16 type;
diff --git a/engines/mohawk/cstime_game.cpp b/engines/mohawk/cstime_game.cpp
index 8eced701c3..c939d8bc24 100644
--- a/engines/mohawk/cstime_game.cpp
+++ b/engines/mohawk/cstime_game.cpp
@@ -94,6 +94,11 @@ CSTimeChar::CSTimeChar(MohawkEngine_CSTime *vm, CSTimeScene *scene, uint id) : _
_lastTime2 = 0;
_lastTime3 = 0;
+ _unknown1 = _unknown2 = _unknown3 = 0;
+ _enabled = false;
+ _nextCue = 0;
+ _waveStatus = 0;
+
_playingWaveId = 0;
}
diff --git a/engines/mohawk/cstime_ui.cpp b/engines/mohawk/cstime_ui.cpp
index f3fe27a966..59be95adf6 100644
--- a/engines/mohawk/cstime_ui.cpp
+++ b/engines/mohawk/cstime_ui.cpp
@@ -79,6 +79,8 @@ CSTimeInterface::CSTimeInterface(MohawkEngine_CSTime *vm) : _vm(vm) {
_rolloverTextFeature = NULL;
_bubbleTextFeature = NULL;
+ _draggedItem = 0;
+
_mouseWasInScene = false;
_state = kCSTimeInterfaceStateNormal;
@@ -1034,6 +1036,8 @@ CSTimeInventoryDisplay::CSTimeInventoryDisplay(MohawkEngine_CSTime *vm, Common::
_cuffsState = false;
_cuffsShape = 10;
+ _draggedItem = 0;
+
_invRect = baseRect;
for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) {
diff --git a/engines/mohawk/cstime_view.cpp b/engines/mohawk/cstime_view.cpp
index 7879175bb0..8727560094 100644
--- a/engines/mohawk/cstime_view.cpp
+++ b/engines/mohawk/cstime_view.cpp
@@ -243,7 +243,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
if ((feature->_flags & kFeatureNewDisable) || (feature->_flags & kFeatureNewDisableOnReset)) {
feature->_data.enabled = 0;
}
- feature->_dirty = 1;
+ feature->_dirty = true;
if (feature->_flags & kFeatureInternalRegion) {
// TODO: create region [+140] (if not already done)
}
@@ -257,7 +257,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
// TODO: or clip with bounds
}
}
- feature->_dirty = 1;
+ feature->_dirty = true;
if (feature->_flags & kFeatureNewInternalTiming) {
feature->_nextTime += feature->_delayTime;
} else {
@@ -277,7 +277,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
}
feature->_data.currOffset = 26;
- feature->_done = 0;
+ feature->_done = false;
}
if (feature->_flags & kFeatureNewDisable)
feature->_data.enabled = 0;
@@ -307,7 +307,7 @@ void CSTimeModule::defaultMoveProc(Feature *feature) {
}
case 0:
// TODO: set ptr +176 to 1
- feature->_done = 1;
+ feature->_done = true;
if (feature->_doneProc) {
(this->*(feature->_doneProc))(feature); // TODO: with -1
}
diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp
index 4b66829e6a..72eebca917 100644
--- a/engines/mohawk/cursors.cpp
+++ b/engines/mohawk/cursors.cpp
@@ -34,8 +34,8 @@
#include "graphics/wincursor.h"
#ifdef ENABLE_MYST
-#include "mohawk/bitmap.h"
#include "mohawk/myst.h"
+#include "mohawk/myst_graphics.h"
#endif
namespace Mohawk {
@@ -86,11 +86,9 @@ void DefaultCursorManager::setCursor(uint16 id) {
#ifdef ENABLE_MYST
MystCursorManager::MystCursorManager(MohawkEngine_Myst *vm) : _vm(vm) {
- _bmpDecoder = new MystBitmap();
}
MystCursorManager::~MystCursorManager() {
- delete _bmpDecoder;
}
void MystCursorManager::showCursor() {
@@ -111,17 +109,18 @@ void MystCursorManager::setCursor(uint16 id) {
return;
}
- // Both Myst and Myst ME use the "MystBitmap" format for cursor images.
- MohawkSurface *mhkSurface = _bmpDecoder->decodeImage(_vm->getResource(ID_WDIB, id));
- Graphics::Surface *surface = mhkSurface->getSurface();
Common::SeekableReadStream *clrcStream = _vm->getResource(ID_CLRC, id);
uint16 hotspotX = clrcStream->readUint16LE();
uint16 hotspotY = clrcStream->readUint16LE();
delete clrcStream;
+ // Both Myst and Myst ME use the "MystBitmap" format for cursor images.
+ MohawkSurface *mhkSurface = _vm->_gfx->findImage(id);
+ Graphics::Surface *surface = mhkSurface->getSurface();
+
// Myst ME stores some cursors as 24bpp images instead of 8bpp
if (surface->format.bytesPerPixel == 1) {
- CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 0);
+ CursorMan.replaceCursor(surface->getPixels(), surface->w, surface->h, hotspotX, hotspotY, 255);
// We're using the screen palette for the original game, but we need
// to use this for any 8bpp cursor in ME.
@@ -133,7 +132,6 @@ void MystCursorManager::setCursor(uint16 id) {
}
_vm->_needsUpdate = true;
- delete mhkSurface;
}
void MystCursorManager::setDefaultCursor() {
diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h
index c41b5c273e..742ae30107 100644
--- a/engines/mohawk/cursors.h
+++ b/engines/mohawk/cursors.h
@@ -102,7 +102,6 @@ enum {
};
class MohawkEngine_Myst;
-class MystBitmap;
// The cursor manager for Myst
// Uses WDIB + CLRC resources
@@ -119,7 +118,6 @@ public:
private:
MohawkEngine_Myst *_vm;
- MystBitmap *_bmpDecoder;
};
#endif // ENABLE_MYST
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 986b35c85e..246d3ec3c1 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -26,6 +26,7 @@
#include "common/savefile.h"
#include "common/system.h"
#include "common/textconsole.h"
+#include "common/translation.h"
#include "mohawk/livingbooks.h"
@@ -40,6 +41,7 @@
#ifdef ENABLE_RIVEN
#include "mohawk/riven.h"
+#include "mohawk/riven_saveload.h"
#endif
namespace Mohawk {
@@ -53,7 +55,7 @@ struct MohawkGameDescription {
};
const char* MohawkEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 MohawkEngine::getFeatures() const {
@@ -160,10 +162,24 @@ static const char *directoryGlobs[] = {
0
};
+static const ADExtraGuiOptionsMap optionsList[] = {
+ {
+ GAMEOPTION_PLAY_MYST_FLYBY,
+ {
+ _s("Play the Myst fly by movie"),
+ _s("The Myst fly by movie was not played by the original engine."),
+ "playmystflyby",
+ false
+ }
+ },
+
+ AD_EXTRA_GUI_OPTIONS_TERMINATOR
+};
+
class MohawkMetaEngine : public AdvancedMetaEngine {
public:
- MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames) {
- _singleid = "mohawk";
+ MohawkMetaEngine() : AdvancedMetaEngine(Mohawk::gameDescriptions, sizeof(Mohawk::MohawkGameDescription), mohawkGames, optionsList) {
+ _singleId = "mohawk";
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
@@ -183,6 +199,7 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual SaveStateList listSaves(const char *target) const;
+ SaveStateList listSavesForPrefix(const char *prefix, const char *extension) const;
virtual int getMaximumSaveSlot() const { return 999; }
virtual void removeSaveState(const char *target, int slot) const;
virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
@@ -199,53 +216,86 @@ bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const {
|| (f == kSavesSupportPlayTime);
}
+SaveStateList MohawkMetaEngine::listSavesForPrefix(const char *prefix, const char *extension) const {
+ Common::String pattern = Common::String::format("%s-###.%s", prefix, extension);
+ Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
+ size_t prefixLen = strlen(prefix);
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
+ // Extract the slot number from the filename
+ char slot[4];
+ slot[0] = (*filename)[prefixLen + 1];
+ slot[1] = (*filename)[prefixLen + 2];
+ slot[2] = (*filename)[prefixLen + 3];
+ slot[3] = '\0';
+
+ int slotNum = atoi(slot);
+
+ saveList.push_back(SaveStateDescriptor(slotNum, ""));
+ }
+
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+
+ return saveList;
+}
+
SaveStateList MohawkMetaEngine::listSaves(const char *target) const {
- Common::StringArray filenames;
SaveStateList saveList;
// Loading games is only supported in Myst/Riven currently.
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- filenames = Mohawk::MystGameState::generateSaveGameList();
+ saveList = listSavesForPrefix("myst", "mys");
- for (uint32 i = 0; i < filenames.size(); i++)
- saveList.push_back(SaveStateDescriptor(i, filenames[i]));
- } else
+ for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
+ // Read the description from the save
+ int slot = save->getSaveSlot();
+ Common::String description = Mohawk::MystGameState::querySaveDescription(slot);
+ save->setDescription(description);
+ }
+ }
#endif
+#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
+ saveList = listSavesForPrefix("riven", "rvn");
- for (uint32 i = 0; i < filenames.size(); i++)
- saveList.push_back(SaveStateDescriptor(i, filenames[i]));
+ for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
+ // Read the description from the save
+ int slot = save->getSaveSlot();
+ Common::String description = Mohawk::RivenSaveLoad::querySaveDescription(slot);
+ save->setDescription(description);
+ }
}
+#endif
return saveList;
}
void MohawkMetaEngine::removeSaveState(const char *target, int slot) const {
+
// Removing saved games is only supported in Myst/Riven currently.
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList();
- Mohawk::MystGameState::deleteSave(filenames[slot]);
- } else
+ Mohawk::MystGameState::deleteSave(slot);
+ }
#endif
+#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
- g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
+ Mohawk::RivenSaveLoad::deleteSave(slot);
}
+#endif
}
SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- Common::StringArray filenames = Mohawk::MystGameState::generateSaveGameList();
-
- if (slot >= (int) filenames.size()) {
- return SaveStateDescriptor();
- }
-
- return Mohawk::MystGameState::querySaveMetaInfos(filenames[slot]);
+ return Mohawk::MystGameState::querySaveMetaInfos(slot);
+ }
+#endif
+#ifdef ENABLE_RIVEN
+ if (strstr(target, "riven")) {
+ return Mohawk::RivenSaveLoad::querySaveMetaInfos(slot);
} else
#endif
{
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index 97d2932d57..d9aba26ca3 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -22,6 +22,13 @@
namespace Mohawk {
+#define GAMEOPTION_PLAY_MYST_FLYBY GUIO_GAMEOPTIONS1
+
+#define GUI_OPTIONS_MYST GUIO3(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI)
+#define GUI_OPTIONS_MYST_ME GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GAMEOPTION_PLAY_MYST_FLYBY)
+#define GUI_OPTIONS_MYST_DEMO GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD)
+#define GUI_OPTIONS_MYST_MAKING_OF GUIO4(GUIO_NOASPECT, GUIO_NOSUBTITLES, GUIO_NOMIDI, GUIO_NOLAUNCHLOAD)
+
static const MohawkGameDescription gameDescriptions[] = {
// Myst
// English Windows 3.11
@@ -33,8 +40,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "ae3258c9c90128d274aa6a790b3ad181"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -51,8 +58,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("DEMO.DAT", "c39303dd53fb5c4e7f3c23231c606cd0"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DEMO | ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_DEMO | ADGF_TESTING,
+ GUI_OPTIONS_MYST_DEMO
},
GType_MYST,
GF_DEMO,
@@ -69,8 +76,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "4beb3366ed3f3b9bfb6e81a14a43bdcc"),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -87,8 +94,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "e0937cca1ab125e48e30dc3cd5046ddf"),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -105,8 +112,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "f7e7d7ca69934f1351b5acd4fe4d44c2"),
Common::ES_ESP,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -123,8 +130,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "a5795ce1751fc42525e4f9a1859181d5"),
Common::IT_ITA,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -141,8 +148,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "032c88e3b7e8db4ca475e7b7db9a66bb"),
Common::JA_JPN,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -159,8 +166,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "d631d42567a941c67c78f2e491f4ea58"),
Common::FR_FRA,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -177,8 +184,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MAKING.DAT", "f6387e8f0f7b8a3e42c95294315d6a0e"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_MAKING_OF
},
GType_MAKINGOF,
0,
@@ -195,8 +202,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MAKING.DAT", "03ff62607e64419ab2b6ebf7b7bcdf63"),
Common::JA_JPN,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_MAKING_OF
},
GType_MAKINGOF,
0,
@@ -213,8 +220,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "c4cae9f143b5947262e6cb2397e1617e"),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -231,8 +238,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "f88e0ace66dbca78eebdaaa1d3314ceb"),
Common::DE_DEU,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -249,8 +256,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "aea81633b2d2ae498f09072fb87263b6"),
Common::FR_FRA,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -267,8 +274,8 @@ static const MohawkGameDescription gameDescriptions[] = {
AD_ENTRY1("MYST.DAT", "4a05771b60f4a69869838d01e85c9e80"),
Common::PL_POL,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
@@ -330,6 +337,24 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.0 (5CD), 1.02 (DVD, From "Myst: La Trilogie")
+ // From gamin
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.0 (5CD) - Italian
// From dodomorandi on bug #6629
{
@@ -348,12 +373,12 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version 1.1 (5CD) - Russian, Fargus
+ // Version 1.0.0 (5CD) - Russian, Fargus
{
{
"riven",
"",
- AD_ENTRY1("a_Data.MHK", "59bd2e3ccbae2f1faa1b23a18dc316eb"),
+ AD_ENTRY1s("a_Data.MHK", "2a840ed74fe5dc3a388bced674d379d5", 12024358),
Common::RU_RUS,
Common::kPlatformWindows,
ADGF_UNSTABLE,
@@ -365,32 +390,31 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version 1.? (DVD, From "Myst 10th Anniversary Edition")
- // From Clone2727
+ // Version 1.1 (5CD) - Russian, Fargus
{
{
"riven",
- "DVD",
- AD_ENTRY1("a_Data.MHK", "08fcaa5d5a2a01d7a5a6960f497212fe"),
- Common::EN_ANY,
+ "",
+ AD_ENTRY1("a_Data.MHK", "59bd2e3ccbae2f1faa1b23a18dc316eb"),
+ Common::RU_RUS,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
},
GType_RIVEN,
- GF_DVD,
+ 0,
0,
},
// Riven: The Sequel to Myst
- // Version 1.0 (DVD, From "Myst: Die Trilogie")
- // From DrMcCoy
+ // Version 1.? (DVD, From "Myst 10th Anniversary Edition")
+ // From Clone2727
{
{
"riven",
- "",
- AD_ENTRY1("a_Data.MHK", "a5fe1c91a6033eb6ee54b287578b74b9"),
- Common::DE_DEU,
+ "DVD",
+ AD_ENTRY1("a_Data.MHK", "08fcaa5d5a2a01d7a5a6960f497212fe"),
+ Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
@@ -401,14 +425,14 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version ? (DVD, From "Myst: La Trilogie")
- // From gamin
+ // Version 1.0 (DVD, From "Myst: Die Trilogie")
+ // From DrMcCoy
{
{
"riven",
"",
- AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
- Common::FR_FRA,
+ AD_ENTRY1("a_Data.MHK", "a5fe1c91a6033eb6ee54b287578b74b9"),
+ Common::DE_DEU,
Common::kPlatformWindows,
ADGF_UNSTABLE,
GUIO1(GUIO_NOASPECT)
@@ -1871,6 +1895,23 @@ static const MohawkGameDescription gameDescriptions[] = {
"Living Books Player"
},
+ // From Matthew Winder in bug#6557
+ // v1.0E, English, Windows
+ {
+ {
+ "arthurbday",
+ "",
+ AD_ENTRY1s("AB16B.LB", "c169be346de7b0bbfcd18761fc0a3e49", 3093),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_LIVINGBOOKSV2,
+ 0,
+ 0,
+ },
+
// From Torsten in bug#3422652
{
{
@@ -2093,6 +2134,22 @@ static const MohawkGameDescription gameDescriptions[] = {
0
},
+ // From Matthew Winder in bug#6557
+ {
+ {
+ "lilmonster",
+ "",
+ AD_ENTRY1s("lmasf.lb", "fcb665df1713d0411a41515efb20bebc", 4136),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_LIVINGBOOKSV2,
+ 0,
+ 0
+ },
+
// From afholman in bug#3309308
{
{
@@ -2697,8 +2754,8 @@ static const MohawkGameDescription fallbackDescs[] = {
AD_ENTRY1(0, 0),
Common::UNK_LANG,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST
},
GType_MYST,
0,
@@ -2712,8 +2769,8 @@ static const MohawkGameDescription fallbackDescs[] = {
AD_ENTRY1(0, 0),
Common::UNK_LANG,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_MAKING_OF
},
GType_MAKINGOF,
0,
@@ -2727,8 +2784,8 @@ static const MohawkGameDescription fallbackDescs[] = {
AD_ENTRY1(0, 0),
Common::UNK_LANG,
Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
+ ADGF_TESTING,
+ GUI_OPTIONS_MYST_ME
},
GType_MYST,
GF_ME,
diff --git a/engines/mohawk/dialogs.cpp b/engines/mohawk/dialogs.cpp
index f8aaf0f4af..8c11e3a5e9 100644
--- a/engines/mohawk/dialogs.cpp
+++ b/engines/mohawk/dialogs.cpp
@@ -25,7 +25,6 @@
#include "gui/gui-manager.h"
#include "gui/saveload.h"
-#include "gui/ThemeEngine.h"
#include "gui/widget.h"
#include "common/system.h"
#include "common/translation.h"
@@ -89,27 +88,11 @@ enum {
kQuitCmd = 'QUIT'
};
-#ifdef ENABLE_MYST
-
-MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0, 360, 200), _vm(vm) {
- // I18N: Option for fast scene switching
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd);
- // I18N: Drop book page
- _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd);
-
- // Myst ME only has maps
- if (_vm->getFeatures() & GF_ME)
- _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd);
- else
- _showMapButton = 0;
-
- // Myst demo only has a menu
- if (_vm->getFeatures() & GF_DEMO)
- _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd);
- else
- _returnToMenuButton = 0;
+#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN)
+MohawkOptionsDialog::MohawkOptionsDialog(MohawkEngine *vm) :
+ GUI::Dialog(0, 0, 360, 200),
+ _vm(vm) {
_loadButton = new GUI::ButtonWidget(this, 245, 25, 100, 25, _("~L~oad"), 0, kLoadCmd);
_saveButton = new GUI::ButtonWidget(this, 245, 60, 100, 25, _("~S~ave"), 0, kSaveCmd);
new GUI::ButtonWidget(this, 245, 95, 100, 25, _("~Q~uit"), 0, kQuitCmd);
@@ -121,37 +104,20 @@ MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : GUI::Dialog(0, 0,
_saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
}
-MystOptionsDialog::~MystOptionsDialog() {
+MohawkOptionsDialog::~MohawkOptionsDialog() {
delete _loadDialog;
delete _saveDialog;
}
-void MystOptionsDialog::open() {
- Dialog::open();
-
- _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0);
-
- if (_showMapButton)
- _showMapButton->setEnabled(_vm->_scriptParser &&
- _vm->_scriptParser->getMap());
-
- // Return to menu button is not enabled on the menu
- if (_returnToMenuButton)
- _returnToMenuButton->setEnabled(_vm->_scriptParser &&
- _vm->getCurStack() != kDemoStack);
-
- // Zip mode is disabled in the demo
- if (_vm->getFeatures() & GF_DEMO)
- _zipModeCheckbox->setEnabled(false);
-
- _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode);
- _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions);
+void MohawkOptionsDialog::open() {
+ GUI::Dialog::open();
_loadButton->setEnabled(_vm->canLoadGameStateCurrently());
_saveButton->setEnabled(_vm->canSaveGameStateCurrently());
}
-void MystOptionsDialog::save() {
+
+void MohawkOptionsDialog::save() {
int slot = _saveDialog->runModalWithCurrentTarget();
if (slot >= 0) {
@@ -166,7 +132,7 @@ void MystOptionsDialog::save() {
}
}
-void MystOptionsDialog::load() {
+void MohawkOptionsDialog::load() {
int slot = _loadDialog->runModalWithCurrentTarget();
if (slot >= 0) {
@@ -175,7 +141,7 @@ void MystOptionsDialog::load() {
}
}
-void MystOptionsDialog::reflowLayout() {
+void MohawkOptionsDialog::reflowLayout() {
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
@@ -183,7 +149,73 @@ void MystOptionsDialog::reflowLayout() {
_x = (screenW - getWidth()) / 2;
_y = (screenH - getHeight()) / 2;
- Dialog::reflowLayout();
+ GUI::Dialog::reflowLayout();
+}
+
+
+void MohawkOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kLoadCmd:
+ load();
+ break;
+ case kSaveCmd:
+ save();
+ break;
+ case GUI::kCloseCmd:
+ close();
+ break;
+ default:
+ GUI::Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+#endif
+
+#ifdef ENABLE_MYST
+
+MystOptionsDialog::MystOptionsDialog(MohawkEngine_Myst* vm) : MohawkOptionsDialog(vm), _vm(vm) {
+ // I18N: Option for fast scene switching
+ _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
+ _transitionsCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~T~ransitions Enabled"), 0, kTransCmd);
+ // I18N: Drop book page
+ _dropPageButton = new GUI::ButtonWidget(this, 15, 60, 100, 25, _("~D~rop Page"), 0, kDropCmd);
+
+ // Myst ME only has maps
+ if (_vm->getFeatures() & GF_ME)
+ _showMapButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Show ~M~ap"), 0, kMapCmd);
+ else
+ _showMapButton = 0;
+
+ // Myst demo only has a menu
+ if (_vm->getFeatures() & GF_DEMO)
+ _returnToMenuButton = new GUI::ButtonWidget(this, 15, 95, 100, 25, _("Main Men~u~"), 0, kMenuCmd);
+ else
+ _returnToMenuButton = 0;
+}
+
+MystOptionsDialog::~MystOptionsDialog() {
+}
+
+void MystOptionsDialog::open() {
+ MohawkOptionsDialog::open();
+
+ _dropPageButton->setEnabled(_vm->_gameState->_globals.heldPage != 0);
+
+ if (_showMapButton)
+ _showMapButton->setEnabled(_vm->_scriptParser &&
+ _vm->_scriptParser->getMap());
+
+ // Return to menu button is not enabled on the menu
+ if (_returnToMenuButton)
+ _returnToMenuButton->setEnabled(_vm->_scriptParser &&
+ _vm->getCurStack() != kDemoStack);
+
+ // Zip mode is disabled in the demo
+ if (_vm->getFeatures() & GF_DEMO)
+ _zipModeCheckbox->setEnabled(false);
+
+ _zipModeCheckbox->setState(_vm->_gameState->_globals.zipMode);
+ _transitionsCheckbox->setState(_vm->_gameState->_globals.transitions);
}
void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
@@ -200,16 +232,14 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
_vm->_needsShowDemoMenu = true;
close();
break;
- case kLoadCmd:
- load();
- break;
- case kSaveCmd:
- save();
- break;
case kQuitCmd: {
- Common::Event eventQ;
- eventQ.type = Common::EVENT_QUIT;
- g_system->getEventManager()->pushEvent(eventQ);
+ if (_vm->getGameType() != GType_MAKINGOF) {
+ _vm->_needsShowCredits = true;
+ } else {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
+ }
close();
}
break;
@@ -219,11 +249,8 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
setResult(1);
close();
break;
- case GUI::kCloseCmd:
- close();
- break;
default:
- GUI::Dialog::handleCommand(sender, cmd, data);
+ MohawkOptionsDialog::handleCommand(sender, cmd, data);
}
}
@@ -231,19 +258,18 @@ void MystOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, ui
#ifdef ENABLE_RIVEN
-RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) : GUI::OptionsDialog("", 120, 120, 360, 200), _vm(vm) {
- _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 300, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
- _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 300, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd);
-
- new GUI::ButtonWidget(this, 95, 160, 120, 25, _("~O~K"), 0, GUI::kOKCmd);
- new GUI::ButtonWidget(this, 225, 160, 120, 25, _("~C~ancel"), 0, GUI::kCloseCmd);
+RivenOptionsDialog::RivenOptionsDialog(MohawkEngine_Riven* vm) :
+ MohawkOptionsDialog(vm),
+ _vm(vm) {
+ _zipModeCheckbox = new GUI::CheckboxWidget(this, 15, 10, 220, 15, _("~Z~ip Mode Activated"), 0, kZipCmd);
+ _waterEffectCheckbox = new GUI::CheckboxWidget(this, 15, 30, 220, 15, _("~W~ater Effect Enabled"), 0, kWaterCmd);
}
RivenOptionsDialog::~RivenOptionsDialog() {
}
void RivenOptionsDialog::open() {
- Dialog::open();
+ MohawkOptionsDialog::open();
_zipModeCheckbox->setState(_vm->_vars["azip"] != 0);
_waterEffectCheckbox->setState(_vm->_vars["waterenabled"] != 0);
@@ -251,17 +277,21 @@ void RivenOptionsDialog::open() {
void RivenOptionsDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
- case kZipCmd:
+ case GUI::kOKCmd:
_vm->_vars["azip"] = _zipModeCheckbox->getState() ? 1 : 0;
- break;
- case kWaterCmd:
_vm->_vars["waterenabled"] = _waterEffectCheckbox->getState() ? 1 : 0;
+ setResult(1);
+ close();
break;
- case GUI::kCloseCmd:
+ case kQuitCmd: {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
close();
break;
+ }
default:
- GUI::OptionsDialog::handleCommand(sender, cmd, data);
+ MohawkOptionsDialog::handleCommand(sender, cmd, data);
}
}
diff --git a/engines/mohawk/dialogs.h b/engines/mohawk/dialogs.h
index bc25c72a43..3cfb628f9d 100644
--- a/engines/mohawk/dialogs.h
+++ b/engines/mohawk/dialogs.h
@@ -28,12 +28,13 @@
#include "common/events.h"
#include "common/str.h"
#include "gui/dialog.h"
-#include "gui/options.h"
-#include "gui/widget.h"
-#include "gui/widgets/list.h"
namespace GUI {
class SaveLoadChooser;
+class ButtonWidget;
+class CheckboxWidget;
+class CommandSender;
+class StaticTextWidget;
}
namespace Mohawk {
@@ -70,18 +71,44 @@ public:
virtual void handleKeyDown(Common::KeyState state);
};
+#if defined(ENABLE_MYST) || defined(ENABLE_RIVEN)
+
+class MohawkOptionsDialog : public GUI::Dialog {
+public:
+ MohawkOptionsDialog(MohawkEngine *_vm);
+ virtual ~MohawkOptionsDialog();
+
+ virtual void open() override;
+ virtual void reflowLayout() override;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
+
+private:
+ MohawkEngine *_vm;
+
+ GUI::ButtonWidget *_loadButton;
+ GUI::ButtonWidget *_saveButton;
+
+ GUI::SaveLoadChooser *_loadDialog;
+ GUI::SaveLoadChooser *_saveDialog;
+
+ void save();
+ void load();
+};
+
+#endif
+
#ifdef ENABLE_MYST
class MohawkEngine_Myst;
-class MystOptionsDialog : public GUI::Dialog {
+class MystOptionsDialog : public MohawkOptionsDialog {
public:
MystOptionsDialog(MohawkEngine_Myst *vm);
- ~MystOptionsDialog();
- void open();
+ virtual ~MystOptionsDialog();
+
+ virtual void open() override;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
- virtual void reflowLayout() override;
- virtual void handleCommand(GUI::CommandSender*, uint32, uint32);
private:
MohawkEngine_Myst *_vm;
@@ -91,15 +118,6 @@ private:
GUI::ButtonWidget *_dropPageButton;
GUI::ButtonWidget *_showMapButton;
GUI::ButtonWidget *_returnToMenuButton;
-
- GUI::ButtonWidget *_loadButton;
- GUI::ButtonWidget *_saveButton;
-
- GUI::SaveLoadChooser *_loadDialog;
- GUI::SaveLoadChooser *_saveDialog;
-
- void save();
- void load();
};
#endif
@@ -108,15 +126,17 @@ private:
class MohawkEngine_Riven;
-class RivenOptionsDialog : public GUI::OptionsDialog {
+class RivenOptionsDialog : public MohawkOptionsDialog {
public:
RivenOptionsDialog(MohawkEngine_Riven *vm);
- ~RivenOptionsDialog();
- void open();
+ virtual ~RivenOptionsDialog();
+
+ virtual void open() override;
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
- virtual void handleCommand(GUI::CommandSender*, uint32, uint32);
private:
MohawkEngine_Riven *_vm;
+
GUI::CheckboxWidget *_zipModeCheckbox;
GUI::CheckboxWidget *_waterEffectCheckbox;
};
diff --git a/engines/mohawk/graphics.h b/engines/mohawk/graphics.h
index 5f9b523e9a..f9fdeea15f 100644
--- a/engines/mohawk/graphics.h
+++ b/engines/mohawk/graphics.h
@@ -74,6 +74,10 @@ public:
// Free all surfaces in the cache
void clearCache();
+ // findImage will search the cache to find the image.
+ // If not found, it will call decodeImage to get a new one.
+ MohawkSurface *findImage(uint16 id);
+
void preloadImage(uint16 image);
virtual void setPalette(uint16 id);
void copyAnimImageToScreen(uint16 image, int left = 0, int top = 0);
@@ -85,10 +89,6 @@ public:
protected:
void copyAnimImageSectionToScreen(MohawkSurface *image, Common::Rect src, Common::Rect dest);
- // findImage will search the cache to find the image.
- // If not found, it will call decodeImage to get a new one.
- MohawkSurface *findImage(uint16 id);
-
// decodeImage will always return a new image.
virtual MohawkSurface *decodeImage(uint16 id) = 0;
virtual Common::Array<MohawkSurface *> decodeImages(uint16 id);
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h
index 6fa733e38e..ac91dca971 100644
--- a/engines/mohawk/mohawk.h
+++ b/engines/mohawk/mohawk.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef MOHAWK_H
-#define MOHAWK_H
+#ifndef MOHAWK_MOHAWK_H
+#define MOHAWK_MOHAWK_H
#include "common/scummsys.h"
#include "common/array.h"
diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp
index 3bc2b2dccb..633b67f7e9 100644
--- a/engines/mohawk/myst.cpp
+++ b/engines/mohawk/myst.cpp
@@ -66,11 +66,6 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription
DebugMan.addDebugChannel(kDebugHelp, "Help", "Track Help File (HELP) Parsing");
DebugMan.addDebugChannel(kDebugCache, "Cache", "Track Resource Cache Accesses");
- // Engine tweaks
- // Disabling this makes engine behavior as per
- // original, including bugs, missing bits etc. :)
- _tweaksEnabled = true;
-
_currentCursor = 0;
_mainCursor = kDefaultMystCursor;
_showResourceRects = false;
@@ -236,11 +231,9 @@ Common::Error MohawkEngine_Myst::run() {
// Load game from launcher/command line if requested
if (ConfMan.hasKey("save_slot") && hasGameSaveSupport()) {
- uint32 gameToLoad = ConfMan.getInt("save_slot");
- Common::StringArray savedGamesList = MystGameState::generateSaveGameList();
- if (gameToLoad > savedGamesList.size())
- error ("Could not find saved game");
- _gameState->load(savedGamesList[gameToLoad]);
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (!_gameState->load(saveSlot))
+ error("Failed to load save game from slot %i", saveSlot);
} else {
// Start us on the first stack.
if (getGameType() == GType_MAKINGOF)
@@ -312,6 +305,7 @@ Common::Error MohawkEngine_Myst::run() {
_needsPageDrop = false;
_needsShowMap = false;
_needsShowDemoMenu = false;
+ _needsShowCredits = false;
_canSafelySaveLoad = true;
runDialog(*_optionsDialog);
@@ -331,6 +325,12 @@ Common::Error MohawkEngine_Myst::run() {
changeToStack(kDemoStack, 2002, 0, 0);
_needsShowDemoMenu = false;
}
+
+ if (_needsShowCredits) {
+ _cursor->hideCursor();
+ changeToStack(kCreditsStack, 10000, 0, 0);
+ _needsShowCredits = false;
+ }
break;
default:
break;
@@ -503,8 +503,9 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS
flyby = "stoneship flyby";
break;
// Myst Flyby Movie not used in Original Masterpiece Edition Engine
+ // We play it when first arriving on Myst, and if the user has chosen so.
case kMystStack:
- if (_tweaksEnabled)
+ if (ConfMan.getBool("playmystflyby") && card == 4134)
flyby = "myst flyby";
break;
case kMechanicalStack:
@@ -603,7 +604,8 @@ void MohawkEngine_Myst::changeToCard(uint16 card, TransitionType transition) {
_gfx->runTransition(transition, Common::Rect(544, 333), 10, 0);
} else {
_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
- _needsUpdate = true;
+ _system->updateScreen();
+ _needsUpdate = false;
}
}
@@ -1080,19 +1082,14 @@ void MohawkEngine_Myst::loadResources() {
}
Common::Error MohawkEngine_Myst::loadGameState(int slot) {
- if (_gameState->load(MystGameState::generateSaveGameList()[slot]))
+ if (_gameState->load(slot))
return Common::kNoError;
return Common::kUnknownError;
}
Common::Error MohawkEngine_Myst::saveGameState(int slot, const Common::String &desc) {
- Common::StringArray saveList = MystGameState::generateSaveGameList();
-
- if ((uint)slot < saveList.size())
- MystGameState::deleteSave(saveList[slot]);
-
- return _gameState->save(desc) ? Common::kNoError : Common::kUnknownError;
+ return _gameState->save(slot, desc) ? Common::kNoError : Common::kUnknownError;
}
bool MohawkEngine_Myst::hasGameSaveSupport() const {
diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h
index 0803c69e55..0b249e5499 100644
--- a/engines/mohawk/myst.h
+++ b/engines/mohawk/myst.h
@@ -192,11 +192,11 @@ public:
MystSoundBlock readSoundBlock(Common::ReadStream *stream) const;
void applySoundBlock(const MystSoundBlock &block);
- bool _tweaksEnabled;
bool _needsUpdate;
bool _needsPageDrop;
bool _needsShowMap;
bool _needsShowDemoMenu;
+ bool _needsShowCredits;
bool _showResourceRects;
diff --git a/engines/mohawk/myst_areas.cpp b/engines/mohawk/myst_areas.cpp
index 59871ed49f..4b9cf546fa 100644
--- a/engines/mohawk/myst_areas.cpp
+++ b/engines/mohawk/myst_areas.cpp
@@ -240,6 +240,7 @@ VideoHandle MystAreaVideo::playMovie() {
} else {
// Resume the video
handle->pause(false);
+ handle->start();
}
if (_playBlocking) {
@@ -250,6 +251,20 @@ VideoHandle MystAreaVideo::playMovie() {
return handle;
}
+VideoHandle MystAreaVideo::getMovieHandle() {
+ // If the video is already in the manager, just return the handle
+ VideoHandle handle = _vm->_video->findVideoHandle(_videoFile);
+ if (!handle) {
+ // If the video has not been loaded yet, do it but don't start playing it
+ handle = _vm->_video->playMovie(_videoFile);
+ if (!handle)
+ error("Failed to open '%s'", _videoFile.c_str());
+ handle->stop();
+ }
+
+ return handle;
+}
+
void MystAreaVideo::handleCardChange() {
if (_playOnCardChange)
playMovie();
diff --git a/engines/mohawk/myst_areas.h b/engines/mohawk/myst_areas.h
index 09ec6a2742..b19a2df9e2 100644
--- a/engines/mohawk/myst_areas.h
+++ b/engines/mohawk/myst_areas.h
@@ -108,6 +108,8 @@ public:
MystAreaVideo(MohawkEngine_Myst *vm, Common::SeekableReadStream *rlstStream, MystArea *parent);
VideoHandle playMovie();
+ VideoHandle getMovieHandle();
+
void handleCardChange() override;
bool isPlaying();
void setDirection(int16 direction) { _direction = direction; }
diff --git a/engines/mohawk/myst_graphics.cpp b/engines/mohawk/myst_graphics.cpp
index 5db9697a78..427fba4d22 100644
--- a/engines/mohawk/myst_graphics.cpp
+++ b/engines/mohawk/myst_graphics.cpp
@@ -47,8 +47,7 @@ MystGraphics::MystGraphics(MohawkEngine_Myst* vm) : GraphicsManager(), _vm(vm) {
} else {
// Paletted
initGraphics(_viewport.width(), _viewport.height(), true);
- setBasePalette();
- setPaletteToScreen();
+ clearScreenPalette();
}
_pixelFormat = _vm->_system->getScreenFormat();
@@ -86,7 +85,7 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
bool isPict = false;
- if (_vm->getFeatures() & GF_ME) {
+ if ((_vm->getFeatures() & GF_ME) && dataStream->size() > 512 + 10 + 4) {
// Here we detect whether it's really a PICT or a WDIB. Since a MystBitmap
// would be compressed, there's no way to detect for the BM without a hack.
// So, we search for the PICT version opcode for detection.
@@ -109,8 +108,11 @@ MohawkSurface *MystGraphics::decodeImage(uint16 id) {
} else {
mhkSurface = _bmpDecoder->decodeImage(dataStream);
- if (_vm->getFeatures() & GF_ME)
+ if (_vm->getFeatures() & GF_ME) {
mhkSurface->convertToTrueColor();
+ } else {
+ remapSurfaceToSystemPalette(mhkSurface);
+ }
}
assert(mhkSurface);
@@ -204,7 +206,7 @@ void MystGraphics::copyImageSectionToBackBuffer(uint16 image, Common::Rect src,
if (!(_vm->getFeatures() & GF_ME)) {
// Make sure the palette is set
assert(mhkSurface->getPalette());
- memcpy(_palette + 10 * 3, mhkSurface->getPalette() + 10 * 3, (256 - 10 * 2) * 3);
+ memcpy(_palette, mhkSurface->getPalette(), 256 * 3);
setPaletteToScreen();
}
}
@@ -703,10 +705,10 @@ void MystGraphics::clearScreenPalette() {
_vm->_system->getPaletteManager()->setPalette(palette, 0, 256);
}
-void MystGraphics::setBasePalette() {
+void MystGraphics::remapSurfaceToSystemPalette(MohawkSurface *mhkSurface) {
// Entries [0, 9] of the palette
static const byte lowPalette[] = {
- 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00,
0x80, 0x00, 0x00,
0x00, 0x80, 0x00,
0x80, 0x80, 0x00,
@@ -729,15 +731,68 @@ void MystGraphics::setBasePalette() {
0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF,
0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x00
+ 0xFF, 0xFF, 0xFF
};
- // Note that 0 and 255 are different from normal Windows.
- // Myst seems to hack that to white, resp. black (probably for Mac compat).
+ byte *originalPalette = mhkSurface->getPalette();
+
+ // The target palette is made of the Windows reserved palette, and colors 10 to 245
+ // of the bitmap palette. Entries 0 to 9 and 246 to 255 of the bitmap palette are
+ // discarded.
+ byte targetPalette[256 * 3];
+ memcpy(targetPalette, lowPalette, sizeof(lowPalette));
+ memcpy(targetPalette + sizeof(lowPalette), originalPalette + sizeof(lowPalette), sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette));
+ memcpy(targetPalette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette));
+
+ // Remap the discarded entries from the bitmap palette using the target palette.
+ byte lowColorMap[ARRAYSIZE(lowPalette) / 3];
+ byte highColorMap[ARRAYSIZE(highPalette) / 3];
+
+ for (uint i = 0; i < ARRAYSIZE(lowColorMap); i++) {
+ uint colorIndex = 3 * i;
+ byte red = originalPalette[colorIndex + 0];
+ byte green = originalPalette[colorIndex + 1];
+ byte blue = originalPalette[colorIndex + 2];
+
+ lowColorMap[i] = getColorIndex(targetPalette, red, green, blue);
+ }
+
+ for (uint i = 0; i < ARRAYSIZE(highColorMap); i++) {
+ uint colorIndex = 3 * (i + 246);
+ byte red = originalPalette[colorIndex + 0];
+ byte green = originalPalette[colorIndex + 1];
+ byte blue = originalPalette[colorIndex + 2];
+
+ highColorMap[i] = getColorIndex(targetPalette, red, green, blue);
+ }
+
+ // Replace the original palette with the target palette
+ memcpy(originalPalette, targetPalette, sizeof(targetPalette));
+
+ // Remap the pixel data to the target palette
+ Graphics::Surface *surface = mhkSurface->getSurface();
+ byte *pixels = (byte *) surface->getPixels();
+
+ for (int i = 0; i < surface->w * surface->h; i++) {
+ if (pixels[i] < ARRAYSIZE(lowColorMap)) {
+ pixels[i] = lowColorMap[pixels[i]];
+ } else if (pixels[i] >= 246) {
+ pixels[i] = highColorMap[pixels[i] - 246];
+ }
+ }
+}
+
+byte MystGraphics::getColorIndex(const byte *palette, byte red, byte green, byte blue) {
+ for (uint i = 0; i < 256; i++) {
+ if (palette[(3 * i) + 0] == red && palette[(3 * i) + 1] == green && palette[(3 * i) + 2] == blue) {
+ return i;
+ }
+ }
- memcpy(_palette, lowPalette, sizeof(lowPalette));
- memset(_palette + sizeof(lowPalette), 0, sizeof(_palette) - sizeof(lowPalette) - sizeof(highPalette));
- memcpy(_palette + sizeof(_palette) - sizeof(highPalette), highPalette, sizeof(highPalette));
+ // GDI actually chooses the nearest color if no exact match is found,
+ // but this should not happen in Myst
+ debug(1, "Color (%d, %d, %d) not in target palette", red, green, blue);
+ return 0;
}
void MystGraphics::setPaletteToScreen() {
diff --git a/engines/mohawk/myst_graphics.h b/engines/mohawk/myst_graphics.h
index 93e388cb83..cd09a53a3a 100644
--- a/engines/mohawk/myst_graphics.h
+++ b/engines/mohawk/myst_graphics.h
@@ -56,7 +56,6 @@ public:
void fadeFromBlack();
void clearScreenPalette();
- void setBasePalette();
void setPaletteToScreen();
const byte *getPalette() const { return _palette; }
@@ -86,6 +85,9 @@ private:
void transitionSlideToBottom(Common::Rect rect, uint16 steps, uint16 delay);
void transitionPartialToRight(Common::Rect rect, uint32 width, uint32 steps);
void transitionPartialToLeft(Common::Rect rect, uint32 width, uint32 steps);
+
+ void remapSurfaceToSystemPalette(MohawkSurface *mhkSurface);
+ byte getColorIndex(const byte *palette, byte red, byte green, byte blue);
};
} // End of namespace Mohawk
diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp
index 04e7c5a9b7..596180ddb2 100644
--- a/engines/mohawk/myst_scripts.cpp
+++ b/engines/mohawk/myst_scripts.cpp
@@ -31,7 +31,6 @@
#include "common/system.h"
#include "common/memstream.h"
#include "common/textconsole.h"
-#include "gui/message.h"
namespace Mohawk {
@@ -685,9 +684,14 @@ void MystScriptParser::o_changeBackgroundSound(uint16 op, uint16 var, uint16 arg
// Used on Channelwood Card 3225 with argc = 8 i.e. Conditional Sound List
debugC(kDebugScript, "Opcode %d: Process Sound Block", op);
- Common::MemoryReadStream stream = Common::MemoryReadStream((const byte *) argv, argc * sizeof(uint16));
+ Common::MemoryWriteStreamDynamic writeStream = Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
+ for (uint i = 0; i < argc; i++) {
+ writeStream.writeUint16LE(argv[i]);
+ }
+
+ Common::MemoryReadStream readStream = Common::MemoryReadStream(writeStream.getData(), writeStream.size());
- MystSoundBlock soundBlock = _vm->readSoundBlock(&stream);
+ MystSoundBlock soundBlock = _vm->readSoundBlock(&readStream);
_vm->applySoundBlock(soundBlock);
}
diff --git a/engines/mohawk/myst_stacks/channelwood.cpp b/engines/mohawk/myst_stacks/channelwood.cpp
index 659c5dcdf2..21c3042359 100644
--- a/engines/mohawk/myst_stacks/channelwood.cpp
+++ b/engines/mohawk/myst_stacks/channelwood.cpp
@@ -621,24 +621,32 @@ void Channelwood::o_hologramMonitor(uint16 op, uint16 var, uint16 argc, uint16 *
switch (button) {
case 0:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monalgh", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monalgh movie");
+ handle->moveTo(227, 70);
break;
case 1:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monamth", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monamth movie");
+ handle->moveTo(227, 70);
break;
case 2:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monasirs", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monasirs movie");
+ handle->moveTo(227, 70);
break;
case 3:
handle = _vm->_video->playMovie(_vm->wrapMovieFilename("monsmsg", kChannelwoodStack));
+ if (!handle)
+ error("Failed to open monsmsg movie");
+ handle->moveTo(226, 68);
break;
default:
warning("Opcode %d Control Variable Out of Range", op);
break;
}
-
- // Move the video to the right location
- if (handle)
- handle->moveTo(227, 70);
}
}
diff --git a/engines/mohawk/myst_stacks/credits.cpp b/engines/mohawk/myst_stacks/credits.cpp
index 6548dd3171..c382263f7c 100644
--- a/engines/mohawk/myst_stacks/credits.cpp
+++ b/engines/mohawk/myst_stacks/credits.cpp
@@ -28,7 +28,6 @@
#include "mohawk/myst_stacks/credits.h"
#include "common/system.h"
-#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
@@ -67,8 +66,10 @@ void Credits::runPersistentScripts() {
_curImage++;
// After the 6th image has shown, it's time to quit
- if (_curImage == 7)
+ if (_curImage == 7) {
_vm->quitGame();
+ return;
+ }
// Draw next image
_vm->drawCardBackground();
diff --git a/engines/mohawk/myst_stacks/intro.cpp b/engines/mohawk/myst_stacks/intro.cpp
index 1d733d8100..f448108199 100644
--- a/engines/mohawk/myst_stacks/intro.cpp
+++ b/engines/mohawk/myst_stacks/intro.cpp
@@ -28,8 +28,6 @@
#include "mohawk/video.h"
#include "mohawk/myst_stacks/intro.h"
-#include "gui/message.h"
-
namespace Mohawk {
namespace MystStacks {
diff --git a/engines/mohawk/myst_stacks/makingof.cpp b/engines/mohawk/myst_stacks/makingof.cpp
index 1059fd0c5e..a0a1f359ba 100644
--- a/engines/mohawk/myst_stacks/makingof.cpp
+++ b/engines/mohawk/myst_stacks/makingof.cpp
@@ -27,8 +27,6 @@
#include "mohawk/video.h"
#include "mohawk/myst_stacks/makingof.h"
-#include "gui/message.h"
-
namespace Mohawk {
namespace MystStacks {
diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp
index 3214c643a5..3324c9a22d 100644
--- a/engines/mohawk/myst_stacks/mechanical.cpp
+++ b/engines/mohawk/myst_stacks/mechanical.cpp
@@ -667,7 +667,7 @@ void Mechanical::o_elevatorTopMovie(uint16 op, uint16 var, uint16 argc, uint16 *
void Mechanical::o_fortressRotationSetPosition(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: Set fortress position", op);
- VideoHandle gears = _fortressRotationGears->playMovie();
+ VideoHandle gears = _fortressRotationGears->getMovieHandle();
uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
// Myst ME short movie workaround, explained in o_fortressRotation_init
@@ -801,7 +801,7 @@ void Mechanical::o_elevatorRotation_init(uint16 op, uint16 var, uint16 argc, uin
}
void Mechanical::fortressRotation_run() {
- VideoHandle gears = _fortressRotationGears->playMovie();
+ VideoHandle gears = _fortressRotationGears->getMovieHandle();
double oldRate = gears->getRate().toDouble();
uint32 moviePosition = Audio::Timestamp(gears->getTime(), 600).totalNumberOfFrames();
@@ -949,7 +949,7 @@ void Mechanical::fortressSimulation_run() {
_fortressSimulationInit = false;
} else {
- VideoHandle holo = _fortressSimulationHolo->playMovie();
+ VideoHandle holo = _fortressSimulationHolo->getMovieHandle();
double oldRate = holo->getRate().toDouble();
diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp
index 5033f0fef8..bd50c4feb3 100644
--- a/engines/mohawk/myst_stacks/myst.cpp
+++ b/engines/mohawk/myst_stacks/myst.cpp
@@ -33,8 +33,6 @@
#include "common/system.h"
#include "common/textconsole.h"
-#include "gui/message.h"
-
namespace Mohawk {
namespace MystStacks {
@@ -52,6 +50,7 @@ Myst::Myst(MohawkEngine_Myst *vm) :
_cabinDoorOpened = 0;
_cabinHandleDown = 0;
_cabinMatchState = 2;
+ _cabinGaugeMovieEnabled = false;
_matchBurning = false;
_tree = nullptr;
_treeAlcove = nullptr;
@@ -2142,7 +2141,7 @@ void Myst::tree_run() {
// Check if alcove is accessible
treeSetAlcoveAccessible();
- if (_cabinGaugeMovie) {
+ if (_cabinGaugeMovieEnabled) {
Common::Rational rate = boilerComputeGaugeRate(pressure, delay);
boilerResetGauge(rate);
}
@@ -2313,7 +2312,7 @@ void Myst::o_rocketPianoStart(uint16 op, uint16 var, uint16 argc, uint16 *argv)
dest.bottom = 332 - rect.top;
// Draw pressed piano key
- _vm->_gfx->copyImageSectionToScreen(key->getSubImage(0).wdib, src, dest);
+ _vm->_gfx->copyImageSectionToScreen(key->getSubImage(1).wdib, src, dest);
_vm->_system->updateScreen();
// Play note
@@ -3088,6 +3087,8 @@ void Myst::clockReset() {
}
void Myst::clockResetWeight() {
+ _vm->_sound->replaceSoundMyst(9113);
+
_clockWeightVideo = _vm->_video->playMovie(_vm->wrapMovieFilename("cl1wlfch", kMystStack));
if (!_clockWeightVideo)
error("Failed to open cl1wlfch movie");
@@ -3703,6 +3704,8 @@ void Myst::boilerGaugeInit() {
frame = Audio::Timestamp(0, 0, 600);
_vm->_video->drawVideoFrame(_cabinGaugeMovie, frame);
+
+ _cabinGaugeMovieEnabled = true;
}
void Myst::o_rocketSliders_init(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@@ -3842,6 +3845,8 @@ void Myst::o_boiler_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
_cabinGaugeMovie = VideoHandle();
_cabinFireMovie = VideoHandle();
+
+ _cabinGaugeMovieEnabled = false;
}
void Myst::o_generatorControlRoom_exit(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
diff --git a/engines/mohawk/myst_stacks/myst.h b/engines/mohawk/myst_stacks/myst.h
index 9d66b798c5..6e2f7cc1c8 100644
--- a/engines/mohawk/myst_stacks/myst.h
+++ b/engines/mohawk/myst_stacks/myst.h
@@ -261,6 +261,8 @@ protected:
uint32 _matchGoOutTime; // 144
VideoHandle _cabinFireMovie; // 240
+
+ bool _cabinGaugeMovieEnabled;
VideoHandle _cabinGaugeMovie; // 244
bool _boilerPressureIncreasing;
diff --git a/engines/mohawk/myst_stacks/selenitic.cpp b/engines/mohawk/myst_stacks/selenitic.cpp
index 2617bd04aa..454435cf92 100644
--- a/engines/mohawk/myst_stacks/selenitic.cpp
+++ b/engines/mohawk/myst_stacks/selenitic.cpp
@@ -31,7 +31,6 @@
#include "common/system.h"
#include "common/textconsole.h"
-#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
@@ -672,6 +671,11 @@ void Selenitic::soundReceiverUpdate() {
}
void Selenitic::soundReceiverDrawView() {
+ soundReceiverSetSubimageRect();
+ soundReceiverDrawAngle();
+}
+
+void Selenitic::soundReceiverSetSubimageRect() const {
uint32 left = ((*_soundReceiverPosition) * 1800) / 3600;
Common::Rect rect = _soundReceiverViewer->getSubImage(0).rect;
@@ -681,8 +685,6 @@ void Selenitic::soundReceiverDrawView() {
_soundReceiverViewer->setSubImageRect(0, rect);
_soundReceiverViewer->drawConditionalDataToScreen(0);
-
- soundReceiverDrawAngle();
}
void Selenitic::soundReceiverDrawAngle() {
@@ -948,10 +950,13 @@ void Selenitic::soundReceiver_run() {
if (_soundReceiverDirection) {
uint32 currentTime = _vm->_system->getMillis();
- if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500)
- soundReceiverIncreaseSpeed();
- else if (currentTime > _soundReceiverStartTime + 1000)
- soundReceiverIncreaseSpeed();
+ if (_soundReceiverSpeed == 50 && currentTime > _soundReceiverStartTime + 500) {
+ soundReceiverIncreaseSpeed();
+ _soundReceiverStartTime = currentTime;
+ } else if (currentTime > _soundReceiverStartTime + 1000) {
+ soundReceiverIncreaseSpeed();
+ _soundReceiverStartTime = currentTime;
+ }
if (currentTime > _soundReceiverStartTime + 100)
soundReceiverUpdate();
@@ -1080,6 +1085,8 @@ void Selenitic::o_soundReceiver_init(uint16 op, uint16 var, uint16 argc, uint16
_soundReceiverPosition = &_state.soundReceiverPositions[currentSource];
_soundReceiverCurrentSource = _soundReceiverSources[currentSource];
+ soundReceiverSetSubimageRect();
+
_soundReceiverSigmaPressed = false;
}
diff --git a/engines/mohawk/myst_stacks/selenitic.h b/engines/mohawk/myst_stacks/selenitic.h
index ffd8941f2c..fc9649755d 100644
--- a/engines/mohawk/myst_stacks/selenitic.h
+++ b/engines/mohawk/myst_stacks/selenitic.h
@@ -117,6 +117,7 @@ private:
void soundReceiverLeftRight(uint direction);
void soundReceiverUpdate();
+ void soundReceiverSetSubimageRect() const;
void soundReceiverDrawView();
void soundReceiverDrawAngle();
void soundReceiverIncreaseSpeed();
diff --git a/engines/mohawk/myst_stacks/slides.cpp b/engines/mohawk/myst_stacks/slides.cpp
index a1413f0d71..0560608b24 100644
--- a/engines/mohawk/myst_stacks/slides.cpp
+++ b/engines/mohawk/myst_stacks/slides.cpp
@@ -29,7 +29,6 @@
#include "mohawk/myst_stacks/slides.h"
#include "common/system.h"
-#include "gui/message.h"
namespace Mohawk {
namespace MystStacks {
diff --git a/engines/mohawk/myst_state.cpp b/engines/mohawk/myst_state.cpp
index 06cd69b23c..213a976413 100644
--- a/engines/mohawk/myst_state.cpp
+++ b/engines/mohawk/myst_state.cpp
@@ -106,16 +106,12 @@ MystGameState::MystGameState(MohawkEngine_Myst *vm, Common::SaveFileManager *sav
MystGameState::~MystGameState() {
}
-Common::StringArray MystGameState::generateSaveGameList() {
- return g_system->getSavefileManager()->listSavefiles("*.mys");
-}
-
-bool MystGameState::load(const Common::String &filename) {
- if (!loadState(filename)) {
+bool MystGameState::load(int slot) {
+ if (!loadState(slot)) {
return false;
}
- loadMetadata(filename);
+ loadMetadata(slot);
// Set Channelwood elevator state to down, because we start on the lower level
_channelwood.elevatorState = 0;
@@ -124,6 +120,7 @@ bool MystGameState::load(const Common::String &filename) {
_vm->changeToStack(kIntroStack, 5, 0, 0);
// Set our default cursor
+ _vm->_cursor->showCursor();
if (_globals.heldPage == 0 || _globals.heldPage > 13)
_vm->setMainCursor(kDefaultMystCursor);
else if (_globals.heldPage < 7)
@@ -136,7 +133,8 @@ bool MystGameState::load(const Common::String &filename) {
return true;
}
-bool MystGameState::loadState(const Common::String &filename) {
+bool MystGameState::loadState(int slot) {
+ Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
if (!loadFile) {
return false;
@@ -160,9 +158,10 @@ bool MystGameState::loadState(const Common::String &filename) {
return true;
}
-void MystGameState::loadMetadata(const Common::String &filename) {
+void MystGameState::loadMetadata(int slot) {
// Open the metadata file
- Common::InSaveFile *metadataFile = openMetadataFile(filename);
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = _vm->getSaveFileManager()->openForLoading(filename);
if (!metadataFile) {
return;
}
@@ -179,25 +178,19 @@ void MystGameState::loadMetadata(const Common::String &filename) {
delete metadataFile;
}
-bool MystGameState::save(const Common::String &filename) {
- // Make sure the description does not have an extension
- Common::String desc = filename;
- if (filename.hasSuffix(".mys") || filename.hasSuffix(".MYS")) {
- desc = removeExtension(filename);
- }
-
- if (!saveState(desc)) {
+bool MystGameState::save(int slot, const Common::String &desc) {
+ if (!saveState(slot)) {
return false;
}
updateMetadateForSaving(desc);
- return saveMetadata(desc);
+ return saveMetadata(slot);
}
-bool MystGameState::saveState(const Common::String &desc) {
+bool MystGameState::saveState(int slot) {
// Make sure we have the right extension
- Common::String filename = desc + ".mys";
+ Common::String filename = buildSaveFilename(slot);
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(filename);
if (!saveFile) {
return false;
@@ -213,6 +206,14 @@ bool MystGameState::saveState(const Common::String &desc) {
return true;
}
+Common::String MystGameState::buildSaveFilename(int slot) {
+ return Common::String::format("myst-%03d.mys", slot);
+}
+
+Common::String MystGameState::buildMetadataFilename(int slot) {
+ return Common::String::format("myst-%03d.mym", slot);
+}
+
void MystGameState::updateMetadateForSaving(const Common::String &desc) {
// Update save creation info
TimeDate t;
@@ -226,10 +227,10 @@ void MystGameState::updateMetadateForSaving(const Common::String &desc) {
_metadata.totalPlayTime = _vm->getTotalPlayTime();
}
-bool MystGameState::saveMetadata(const Common::String &desc) {
+bool MystGameState::saveMetadata(int slot) {
// Write the metadata to a separate file so that the save files
// are still compatible with the original engine
- Common::String metadataFilename = desc + ".mym";
+ Common::String metadataFilename = buildMetadataFilename(slot);
Common::OutSaveFile *metadataFile = _saveFileMan->openForSaving(metadataFilename);
if (!metadataFile) {
return false;
@@ -248,14 +249,12 @@ bool MystGameState::saveMetadata(const Common::String &desc) {
return true;
}
-SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filename) {
- SaveStateDescriptor desc;
- desc.setDescription(filename);
-
+SaveStateDescriptor MystGameState::querySaveMetaInfos(int slot) {
// Open the metadata file
- Common::InSaveFile *metadataFile = openMetadataFile(filename);
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
if (!metadataFile) {
- return desc;
+ return SaveStateDescriptor();
}
Common::Serializer m(metadataFile, nullptr);
@@ -264,10 +263,11 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filen
Mohawk::MystSaveMetadata metadata;
if (!metadata.sync(m)) {
delete metadataFile;
- return desc;
+ return SaveStateDescriptor();
}
// Set the save description
+ SaveStateDescriptor desc;
desc.setDescription(metadata.saveDescription);
desc.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
desc.setSaveTime(metadata.saveHour, metadata.saveMinute);
@@ -279,20 +279,26 @@ SaveStateDescriptor MystGameState::querySaveMetaInfos(const Common::String filen
return desc;
}
-Common::InSaveFile *MystGameState::openMetadataFile(const Common::String &filename) {
- // Remove the extension
- Common::String baseName = removeExtension(filename);
-
+Common::String MystGameState::querySaveDescription(int slot) {
// Open the metadata file
- return g_system->getSavefileManager()->openForLoading(baseName + ".mym");
-}
+ Common::String filename = buildMetadataFilename(slot);
+ Common::InSaveFile *metadataFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!metadataFile) {
+ return "";
+ }
+
+ Common::Serializer m(metadataFile, nullptr);
-Common::String MystGameState::removeExtension(const Common::String &filename) {
- Common::String baseName = filename;
- for (uint i = 0; i < 4; i++) {
- baseName.deleteLastChar();
+ // Read the metadata file
+ Mohawk::MystSaveMetadata metadata;
+ if (!metadata.sync(m)) {
+ delete metadataFile;
+ return "";
}
- return baseName;
+
+ delete metadataFile;
+
+ return metadata.saveDescription;
}
void MystGameState::syncGameState(Common::Serializer &s, bool isME) {
@@ -471,12 +477,14 @@ void MystGameState::syncGameState(Common::Serializer &s, bool isME) {
warning("Unexpected File Position 0x%03X At End of Save/Load", s.bytesSynced());
}
-void MystGameState::deleteSave(const Common::String &saveName) {
- debugC(kDebugSaveLoad, "Deleting save file \'%s\'", saveName.c_str());
- Common::String basename = removeExtension(saveName);
+void MystGameState::deleteSave(int slot) {
+ Common::String filename = buildSaveFilename(slot);
+ Common::String metadataFilename = buildMetadataFilename(slot);
+
+ debugC(kDebugSaveLoad, "Deleting save file \'%s\'", filename.c_str());
- g_system->getSavefileManager()->removeSavefile(saveName);
- g_system->getSavefileManager()->removeSavefile(basename + ".mym");
+ g_system->getSavefileManager()->removeSavefile(filename);
+ g_system->getSavefileManager()->removeSavefile(metadataFilename);
}
void MystGameState::addZipDest(uint16 stack, uint16 view) {
diff --git a/engines/mohawk/myst_state.h b/engines/mohawk/myst_state.h
index 50359a5b52..7d5f3f7102 100644
--- a/engines/mohawk/myst_state.h
+++ b/engines/mohawk/myst_state.h
@@ -58,12 +58,12 @@ public:
MystGameState(MohawkEngine_Myst*, Common::SaveFileManager*);
~MystGameState();
- static Common::StringArray generateSaveGameList();
- static SaveStateDescriptor querySaveMetaInfos(const Common::String filename);
+ static SaveStateDescriptor querySaveMetaInfos(int slot);
+ static Common::String querySaveDescription(int slot);
- bool load(const Common::String &filename);
- bool save(const Common::String &filename);
- static void deleteSave(const Common::String &saveName);
+ bool load(int slot);
+ bool save(int slot, const Common::String &desc);
+ static void deleteSave(int slot);
void addZipDest(uint16 stack, uint16 view);
bool isReachableZipDest(uint16 stack, uint16 view);
@@ -292,13 +292,13 @@ public:
private:
void syncGameState(Common::Serializer &s, bool isME);
- static Common::InSaveFile *openMetadataFile(const Common::String &filename);
- bool loadState(const Common::String &filename);
- void loadMetadata(const Common::String &filename);
- bool saveState(const Common::String &desc);
+ static Common::String buildSaveFilename(int slot);
+ static Common::String buildMetadataFilename(int slot);
+ bool loadState(int slot);
+ void loadMetadata(int slot);
+ bool saveState(int slot);
void updateMetadateForSaving(const Common::String &desc);
- bool saveMetadata(const Common::String &desc);
- static Common::String removeExtension(const Common::String &filename);
+ bool saveMetadata(int slot);
// The values in these regions are lists of VIEW resources
// which correspond to visited zip destinations
diff --git a/engines/mohawk/resource.h b/engines/mohawk/resource.h
index d9074a5b73..12c5a139e4 100644
--- a/engines/mohawk/resource.h
+++ b/engines/mohawk/resource.h
@@ -68,6 +68,8 @@ namespace Mohawk {
#define ID_VARS MKTAG('V','A','R','S') // Variable Values
#define ID_VERS MKTAG('V','E','R','S') // Version Info
#define ID_ZIPS MKTAG('Z','I','P','S') // Zip Mode Status
+#define ID_META MKTAG('M','E','T','A') // ScummVM save metadata
+#define ID_THMB MKTAG('T','H','M','B') // ScummVM save thumbnail
// Zoombini Resource FourCC's
#define ID_SND MKTAG( 0 ,'S','N','D') // Standard Mohawk Sound
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 898f68c581..aa168a38d8 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -25,6 +25,7 @@
#include "common/keyboard.h"
#include "common/translation.h"
#include "common/system.h"
+#include "gui/saveload.h"
#include "mohawk/cursors.h"
#include "mohawk/installer_archive.h"
@@ -54,9 +55,19 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio
_gameOver = false;
_activatedSLST = false;
_ignoreNextMouseUp = false;
- _extrasFile = 0;
+ _extrasFile = nullptr;
_curStack = kStackUnknown;
- _hotspots = 0;
+ _hotspots = nullptr;
+ _gfx = nullptr;
+ _externalScriptHandler = nullptr;
+ _rnd = nullptr;
+ _scriptMan = nullptr;
+ _console = nullptr;
+ _saveLoad = nullptr;
+ _optionsDialog = nullptr;
+ _curCard = 0;
+ _hotspotCount = 0;
+ _curHotspot = -1;
removeTimer();
// NOTE: We can never really support CD swapping. All of the music files
@@ -165,13 +176,10 @@ Common::Error MohawkEngine_Riven::run() {
changeToCard(6);
} else if (ConfMan.hasKey("save_slot")) {
// Load game from launcher/command line if requested
- uint32 gameToLoad = ConfMan.getInt("save_slot");
- Common::StringArray savedGamesList = _saveLoad->generateSaveGameList();
- if (gameToLoad > savedGamesList.size())
- error ("Could not find saved game");
+ int gameToLoad = ConfMan.getInt("save_slot");
// Attempt to load the game. On failure, just send us to the main menu.
- if (_saveLoad->loadGame(savedGamesList[gameToLoad]).getCode() != Common::kNoError) {
+ if (_saveLoad->loadGame(gameToLoad).getCode() != Common::kNoError) {
changeToStack(kStackAspit);
changeToCard(1);
}
@@ -723,16 +731,11 @@ void MohawkEngine_Riven::runLoadDialog() {
}
Common::Error MohawkEngine_Riven::loadGameState(int slot) {
- return _saveLoad->loadGame(_saveLoad->generateSaveGameList()[slot]);
+ return _saveLoad->loadGame(slot);
}
Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) {
- Common::StringArray saveList = _saveLoad->generateSaveGameList();
-
- if ((uint)slot < saveList.size())
- _saveLoad->deleteSave(saveList[slot]);
-
- return _saveLoad->saveGame(desc);
+ return _saveLoad->saveGame(slot, desc);
}
Common::String MohawkEngine_Riven::getStackName(uint16 stack) const {
diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h
index 9c23d07c52..3ea50bb38d 100644
--- a/engines/mohawk/riven.h
+++ b/engines/mohawk/riven.h
@@ -27,8 +27,6 @@
#include "mohawk/mohawk.h"
#include "mohawk/riven_scripts.h"
-#include "gui/saveload.h"
-
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/random.h"
diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp
index b44fbb828e..db22dde22d 100644
--- a/engines/mohawk/riven_graphics.cpp
+++ b/engines/mohawk/riven_graphics.cpp
@@ -51,6 +51,8 @@ RivenGraphics::RivenGraphics(MohawkEngine_Riven* vm) : GraphicsManager(), _vm(vm
_creditsImage = 302;
_creditsPos = 0;
+
+ _transitionSpeed = 0;
}
RivenGraphics::~RivenGraphics() {
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 6af66f7a2d..755f87767d 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -24,25 +24,141 @@
#include "mohawk/riven.h"
#include "mohawk/riven_saveload.h"
-#include "common/util.h"
+#include "common/system.h"
+#include "graphics/thumbnail.h"
namespace Mohawk {
+RivenSaveMetadata::RivenSaveMetadata() {
+ saveDay = 0;
+ saveMonth = 0;
+ saveYear = 0;
+ saveHour = 0;
+ saveMinute = 0;
+ totalPlayTime = 0;
+}
+
+bool RivenSaveMetadata::sync(Common::Serializer &s) {
+ static const Common::Serializer::Version kCurrentVersion = 1;
+
+ if (!s.syncVersion(kCurrentVersion)) {
+ return false;
+ }
+
+ s.syncAsByte(saveDay);
+ s.syncAsByte(saveMonth);
+ s.syncAsUint16BE(saveYear);
+ s.syncAsByte(saveHour);
+ s.syncAsByte(saveMinute);
+ s.syncString(saveDescription);
+ s.syncAsUint32BE(totalPlayTime);
+
+ return true;
+}
+
RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
}
RivenSaveLoad::~RivenSaveLoad() {
}
-Common::StringArray RivenSaveLoad::generateSaveGameList() {
- return _saveFileMan->listSavefiles("*.rvn");
+Common::String RivenSaveLoad::buildSaveFilename(const int slot) {
+ return Common::String::format("riven-%03d.rvn", slot);
+}
+
+Common::String RivenSaveLoad::querySaveDescription(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return "";
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return "";
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return "";
+ }
+
+ Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
+ if (!metaStream) {
+ return "";
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ delete metaStream;
+ return "";
+ }
+
+ delete metaStream;
+
+ return metadata.saveDescription;
}
-Common::Error RivenSaveLoad::loadGame(Common::String filename) {
+SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return SaveStateDescriptor();
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return SaveStateDescriptor();
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return SaveStateDescriptor();
+ }
+
+ Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
+ if (!metaStream) {
+ return SaveStateDescriptor();
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ delete metaStream;
+ return SaveStateDescriptor();
+ }
+
+ SaveStateDescriptor descriptor;
+ descriptor.setDescription(metadata.saveDescription);
+ descriptor.setPlayTime(metadata.totalPlayTime);
+ descriptor.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
+ descriptor.setSaveTime(metadata.saveHour, metadata.saveMinute);
+
+ delete metaStream;
+
+ if (!mhk.hasResource(ID_THMB, 1)) {
+ return descriptor;
+ }
+
+ Common::SeekableReadStream *thmbStream = mhk.getResource(ID_THMB, 1);
+ if (!thmbStream) {
+ return descriptor;
+ }
+
+ descriptor.setThumbnail(Graphics::loadThumbnail(*thmbStream));
+
+ delete thmbStream;
+
+ return descriptor;
+}
+
+Common::Error RivenSaveLoad::loadGame(const int slot) {
if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo
return Common::kNoError;
- Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
+ Common::String filename = buildSaveFilename(slot);
+ Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
if (!loadFile)
return Common::kReadingFailed;
@@ -72,8 +188,11 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) {
Common::Array<uint32> rawVariables;
while (!vars->eos()) {
- vars->readUint32BE(); // Unknown (Stack?)
- vars->readUint32BE(); // Unknown (0 or 1)
+ // The original engine stores the variables values in an array. All the slots in
+ // the array may not be in use, which is why it needs a reference counter and
+ // a flag to tell if the value has been set.
+ vars->readUint32BE(); // Reference counter
+ vars->readUint32BE(); // Variable initialized flag
rawVariables.push_back(vars->readUint32BE());
}
@@ -144,6 +263,20 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) {
}
delete zips;
+
+ // Load the ScummVM specific save metadata
+ if (mhk->hasResource(ID_META, 1)) {
+ Common::SeekableReadStream *metadataStream = mhk->getResource(ID_META, 1);
+ Common::Serializer serializer = Common::Serializer(metadataStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ metadata.sync(serializer);
+
+ // Set the saved total play time
+ _vm->setTotalPlayTime(metadata.totalPlayTime);
+
+ delete metadataStream;
+ }
delete mhk;
return Common::kNoError;
@@ -162,14 +295,18 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genVARSSection() {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
- stream->writeUint32BE(0); // Unknown
- stream->writeUint32BE(0); // Unknown
+ stream->writeUint32BE(1); // Reference counter
+ stream->writeUint32BE(1); // Variable initialized flag
stream->writeUint32BE(it->_value);
}
return stream;
}
+static int stringCompareToIgnoreCase(const Common::String &s1, const Common::String &s2) {
+ return s1.compareToIgnoreCase(s2) < 0;
+}
+
Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
@@ -181,8 +318,28 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() {
curPos += it->_key.size() + 1;
}
- for (uint16 i = 0; i < _vm->_vars.size(); i++)
- stream->writeUint16BE(i);
+ // The original engine does not store the variables in a HashMap, but in a "NameList"
+ // for the keys and an array for the values. The NameList data structure maintains an array
+ // of indices in the string table sorted by case insensitive key alphabetical order.
+ // It is used to perform fast key -> index lookups.
+ // ScummVM does not need the sorted array, but has to write it anyway for the saved games
+ // to be compatible with original engine.
+ Common::Array<Common::String> sortedKeys;
+ for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
+ sortedKeys.push_back(it->_key);
+ }
+ Common::sort(sortedKeys.begin(), sortedKeys.end(), stringCompareToIgnoreCase);
+
+ for (uint i = 0; i < sortedKeys.size(); i++) {
+ uint16 varIndex = 0;
+ for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
+ if (it->_key == sortedKeys[i]) {
+ stream->writeUint16BE(varIndex);
+ break;
+ }
+ varIndex++;
+ }
+ }
for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
stream->write(it->_key.c_str(), it->_key.size());
@@ -206,7 +363,35 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genZIPSSection() {
return stream;
}
-Common::Error RivenSaveLoad::saveGame(Common::String filename) {
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genTHMBSection() const {
+ Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
+
+ Graphics::saveThumbnail(*stream);
+
+ return stream;
+}
+
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc) const {
+ Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
+ Common::Serializer serializer = Common::Serializer(nullptr, stream);
+
+ TimeDate t;
+ _vm->_system->getTimeAndDate(t);
+
+ RivenSaveMetadata metadata;
+ metadata.saveDay = t.tm_mday;
+ metadata.saveMonth = t.tm_mon + 1;
+ metadata.saveYear = t.tm_year + 1900;
+ metadata.saveHour = t.tm_hour;
+ metadata.saveMinute = t.tm_min;
+ metadata.saveDescription = desc;
+ metadata.totalPlayTime = _vm->getTotalPlayTime();
+ metadata.sync(serializer);
+
+ return stream;
+}
+
+Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description) {
// NOTE: This code is designed to only output a Mohawk archive
// for a Riven saved game. It's hardcoded to do this because
// (as of right now) this is the only place in the engine
@@ -214,13 +399,7 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// games need this, we should think about coming up with some
// more common way of outputting resources to an archive.
- // TODO: Make these saves work with the original interpreter.
- // Not sure why they don't work yet (they still can be loaded
- // by ScummVM).
-
- // Make sure we have the right extension
- if (!filename.matchString("*.rvn", true))
- filename += ".rvn";
+ Common::String filename = buildSaveFilename(slot);
// Convert class variables to variable numbers
_vm->_vars["currentstackid"] = _vm->getCurStack();
@@ -232,16 +411,20 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
debug (0, "Saving game to \'%s\'", filename.c_str());
- Common::MemoryWriteStreamDynamic *versSection = genVERSSection();
+ Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description);
Common::MemoryWriteStreamDynamic *nameSection = genNAMESection();
+ Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection();
Common::MemoryWriteStreamDynamic *varsSection = genVARSSection();
+ Common::MemoryWriteStreamDynamic *versSection = genVERSSection();
Common::MemoryWriteStreamDynamic *zipsSection = genZIPSSection();
// Let's calculate the file size!
- uint32 fileSize = 142;
- fileSize += versSection->size();
+ uint32 fileSize = 194;
+ fileSize += metaSection->size();
fileSize += nameSection->size();
+ fileSize += thmbSection->size();
fileSize += varsSection->size();
+ fileSize += versSection->size();
fileSize += zipsSection->size();
// MHWK Header (8 bytes - total: 8)
@@ -254,109 +437,151 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
saveFile->writeUint16BE(1); // Compaction -- original saves have this too
saveFile->writeUint32BE(fileSize); // Subtract off the MHWK header size
saveFile->writeUint32BE(28); // Absolute offset: right after both headers
- saveFile->writeUint16BE(70); // File Table Offset
- saveFile->writeUint16BE(44); // File Table Size (4 bytes count + 4 entries * 10 bytes per entry)
+ saveFile->writeUint16BE(102); // File Table Offset
+ saveFile->writeUint16BE(64); // File Table Size (4 bytes count + 6 entries * 10 bytes per entry)
// Type Table (4 bytes - total: 32)
- saveFile->writeUint16BE(36); // String table offset After the Type Table Entries
- saveFile->writeUint16BE(4); // 4 Type Table Entries
+ saveFile->writeUint16BE(52); // String table offset After the Type Table Entries
+ saveFile->writeUint16BE(6); // 6 Type Table Entries
- // Hardcode Entries (32 bytes - total: 64)
- saveFile->writeUint32BE(ID_VERS);
- saveFile->writeUint16BE(46); // Resource table offset
- saveFile->writeUint16BE(38); // String table offset
+ // Hardcode Entries (48 bytes - total: 80)
+ // The original engine relies on the entries being sorted by tag alphabetical order
+ // to optimize its lookup algorithm.
+ saveFile->writeUint32BE(ID_META);
+ saveFile->writeUint16BE(66); // Resource table offset
+ saveFile->writeUint16BE(54); // String table offset
saveFile->writeUint32BE(ID_NAME);
- saveFile->writeUint16BE(52);
- saveFile->writeUint16BE(40);
+ saveFile->writeUint16BE(72);
+ saveFile->writeUint16BE(56);
- saveFile->writeUint32BE(ID_VARS);
+ saveFile->writeUint32BE(ID_THMB);
+ saveFile->writeUint16BE(78);
saveFile->writeUint16BE(58);
- saveFile->writeUint16BE(42);
+
+ saveFile->writeUint32BE(ID_VARS);
+ saveFile->writeUint16BE(84);
+ saveFile->writeUint16BE(60);
+
+ saveFile->writeUint32BE(ID_VERS);
+ saveFile->writeUint16BE(90);
+ saveFile->writeUint16BE(62);
saveFile->writeUint32BE(ID_ZIPS);
+ saveFile->writeUint16BE(96);
saveFile->writeUint16BE(64);
- saveFile->writeUint16BE(44);
- // Pseudo-String Table (2 bytes - total: 66)
+ // Pseudo-String Table (2 bytes - total: 82)
saveFile->writeUint16BE(0); // We don't need a name list
- // Psuedo-Name Tables (8 bytes - total: 74)
+ // Pseudo-Name Tables (12 bytes - total: 94)
+ saveFile->writeUint16BE(0);
+ saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
- // VERS Section (Resource Table) (6 bytes - total: 80)
+ // META Section (Resource Table) (6 bytes - total: 100)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
- // NAME Section (Resource Table) (6 bytes - total: 86)
+ // NAME Section (Resource Table) (6 bytes - total: 106)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(2);
- // VARS Section (Resource Table) (6 bytes - total: 92)
+ // THMB Section (Resource Table) (6 bytes - total: 112)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(3);
- // ZIPS Section (Resource Table) (6 bytes - total: 98)
+ // VARS Section (Resource Table) (6 bytes - total: 118)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(4);
- // File Table (4 bytes - total: 102)
- saveFile->writeUint32BE(4);
+ // VERS Section (Resource Table) (6 bytes - total: 124)
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(5);
- // VERS Section (File Table) (10 bytes - total: 112)
- saveFile->writeUint32BE(142);
- saveFile->writeUint16BE(versSection->size() & 0xFFFF);
- saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
+ // ZIPS Section (Resource Table) (6 bytes - total: 130)
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(6);
+
+ // File Table (4 bytes - total: 134)
+ saveFile->writeUint32BE(6);
+
+ // META Section (File Table) (10 bytes - total: 144)
+ saveFile->writeUint32BE(194);
+ saveFile->writeUint16BE(metaSection->size() & 0xFFFF);
+ saveFile->writeByte((metaSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // NAME Section (File Table) (10 bytes - total: 122)
- saveFile->writeUint32BE(142 + versSection->size());
+ // NAME Section (File Table) (10 bytes - total: 154)
+ saveFile->writeUint32BE(194 + metaSection->size());
saveFile->writeUint16BE(nameSection->size() & 0xFFFF);
saveFile->writeByte((nameSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // VARS Section (File Table) (10 bytes - total: 132)
- saveFile->writeUint32BE(142 + versSection->size() + nameSection->size());
+ // THMB Section (File Table) (10 bytes - total: 164)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size());
+ saveFile->writeUint16BE(thmbSection->size() & 0xFFFF);
+ saveFile->writeByte((thmbSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
+ // VARS Section (File Table) (10 bytes - total: 174)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size());
saveFile->writeUint16BE(varsSection->size() & 0xFFFF);
saveFile->writeByte((varsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // ZIPS Section (File Table) (10 bytes - total: 142)
- saveFile->writeUint32BE(142 + versSection->size() + nameSection->size() + varsSection->size());
+ // VERS Section (File Table) (10 bytes - total: 184)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size());
+ saveFile->writeUint16BE(versSection->size() & 0xFFFF);
+ saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
+ // ZIPS Section (File Table) (10 bytes - total: 194)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size() + versSection->size());
saveFile->writeUint16BE(zipsSection->size() & 0xFFFF);
saveFile->writeByte((zipsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- saveFile->write(versSection->getData(), versSection->size());
+ saveFile->write(metaSection->getData(), metaSection->size());
saveFile->write(nameSection->getData(), nameSection->size());
+ saveFile->write(thmbSection->getData(), thmbSection->size());
saveFile->write(varsSection->getData(), varsSection->size());
+ saveFile->write(versSection->getData(), versSection->size());
saveFile->write(zipsSection->getData(), zipsSection->size());
saveFile->finalize();
delete saveFile;
- delete versSection;
+ delete metaSection;
delete nameSection;
+ delete thmbSection;
delete varsSection;
+ delete versSection;
delete zipsSection;
return Common::kNoError;
}
-void RivenSaveLoad::deleteSave(Common::String saveName) {
- debug (0, "Deleting save file \'%s\'", saveName.c_str());
- _saveFileMan->removeSavefile(saveName);
+void RivenSaveLoad::deleteSave(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+
+ debug (0, "Deleting save file \'%s\'", filename.c_str());
+ g_system->getSavefileManager()->removeSavefile(filename);
}
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h
index a6ddce5713..34bfbdc434 100644
--- a/engines/mohawk/riven_saveload.h
+++ b/engines/mohawk/riven_saveload.h
@@ -23,10 +23,13 @@
#ifndef MOHAWK_SAVELOAD_H
#define MOHAWK_SAVELOAD_H
+#include "common/serializer.h"
#include "common/savefile.h"
#include "common/str.h"
#include "common/memstream.h"
+#include "engines/savestate.h"
+
namespace Mohawk {
class MohawkEngine_Riven;
@@ -36,23 +39,45 @@ enum {
kDVDSaveGameVersion = 0x00010100
};
+struct RivenSaveMetadata {
+ uint8 saveDay;
+ uint8 saveMonth;
+ uint16 saveYear;
+
+ uint8 saveHour;
+ uint8 saveMinute;
+
+ uint32 totalPlayTime;
+
+ Common::String saveDescription;
+
+ RivenSaveMetadata();
+ bool sync(Common::Serializer &s);
+};
+
class RivenSaveLoad {
public:
RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*);
~RivenSaveLoad();
- Common::StringArray generateSaveGameList();
- Common::Error loadGame(Common::String);
- Common::Error saveGame(Common::String);
- void deleteSave(Common::String);
+ Common::Error loadGame(const int slot);
+ Common::Error saveGame(const int slot, const Common::String &description);
+ static void deleteSave(const int slot);
+
+ static SaveStateDescriptor querySaveMetaInfos(const int slot);
+ static Common::String querySaveDescription(const int slot);
private:
MohawkEngine_Riven *_vm;
Common::SaveFileManager *_saveFileMan;
- Common::MemoryWriteStreamDynamic *genVERSSection();
+ static Common::String buildSaveFilename(const int slot);
+
Common::MemoryWriteStreamDynamic *genNAMESection();
+ Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const;
+ Common::MemoryWriteStreamDynamic *genTHMBSection() const;
Common::MemoryWriteStreamDynamic *genVARSSection();
+ Common::MemoryWriteStreamDynamic *genVERSSection();
Common::MemoryWriteStreamDynamic *genZIPSSection();
};
diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp
index a2c08d4a92..38cb0b3608 100644
--- a/engines/mohawk/sound.cpp
+++ b/engines/mohawk/sound.cpp
@@ -23,12 +23,12 @@
#include "common/debug.h"
#include "common/events.h"
#include "common/system.h"
-#include "common/util.h"
#include "common/textconsole.h"
+#include "audio/mididrv.h"
#include "audio/midiparser.h"
-#include "audio/musicplugin.h"
#include "audio/audiostream.h"
+#include "audio/decoders/adpcm.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/wave.h"
diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h
index c62e6e9874..f09706e155 100644
--- a/engines/mohawk/sound.h
+++ b/engines/mohawk/sound.h
@@ -26,9 +26,7 @@
#include "common/scummsys.h"
#include "common/str.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
-#include "audio/decoders/adpcm.h"
#include "mohawk/mohawk.h"
#include "mohawk/resource.h"
@@ -36,6 +34,10 @@
class MidiDriver;
class MidiParser;
+namespace Audio {
+class RewindableAudioStream;
+}
+
namespace Mohawk {
#define MAX_CHANNELS 2 // Can there be more than 2?
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index 522dd5ecdd..eec543235e 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -146,7 +146,7 @@ VideoHandle::VideoHandle(const VideoHandle &handle) : _ptr(handle._ptr) {
VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
// Set dithering enabled, if required
- _enableDither = _vm->getGameType() == GType_MYST && !(_vm->getFeatures() & GF_ME);
+ _enableDither = (_vm->getGameType() == GType_MYST || _vm->getGameType() == GType_MAKINGOF) && !(_vm->getFeatures() & GF_ME);
}
VideoManager::~VideoManager() {
@@ -317,69 +317,8 @@ bool VideoManager::updateMovies() {
// Check if we need to draw a frame
if (video->needsUpdate()) {
- const Graphics::Surface *frame = video->decodeNextFrame();
- Graphics::Surface *convertedFrame = 0;
-
- if (frame && (*it)->isEnabled()) {
- Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
-
- if (frame->format != pixelFormat) {
- // We don't support downconverting to 8bpp without having
- // support in the codec. Set _enableDither if shows up.
- if (pixelFormat.bytesPerPixel == 1) {
- warning("Cannot convert high color video frame to 8bpp");
- (*it)->close();
- it = _videos.erase(it);
- continue;
- }
-
- // Convert to the current screen format
- convertedFrame = frame->convertTo(pixelFormat, video->getPalette());
- frame = convertedFrame;
- } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) {
- // Set the palette when running in 8bpp mode only
- // Don't do this for Myst, which has its own per-stack handling
- if (_vm->getGameType() != GType_MYST)
- _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256);
- }
-
- // Clip the video to make sure it stays on the screen (Myst does this a few times)
- Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight());
- targetRect.translate((*it)->getX(), (*it)->getY());
-
- Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight());
-
- if (targetRect.left < 0) {
- frameRect.left -= targetRect.left;
- targetRect.left = 0;
- }
-
- if (targetRect.top < 0) {
- frameRect.top -= targetRect.top;
- targetRect.top = 0;
- }
-
- if (targetRect.right > _vm->_system->getWidth()) {
- frameRect.right -= targetRect.right - _vm->_system->getWidth();
- targetRect.right = _vm->_system->getWidth();
- }
-
- if (targetRect.bottom > _vm->_system->getHeight()) {
- frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight();
- targetRect.bottom = _vm->_system->getHeight();
- }
-
- _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch,
- targetRect.left, targetRect.top, targetRect.width(), targetRect.height());
-
- // We've drawn something to the screen, make sure we update it
+ if (drawNextFrame(*it)) {
updateScreen = true;
-
- // Delete 8bpp conversion surface
- if (convertedFrame) {
- convertedFrame->free();
- delete convertedFrame;
- }
}
}
@@ -394,6 +333,74 @@ bool VideoManager::updateMovies() {
return updateScreen;
}
+bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) {
+ Video::VideoDecoder *video = videoEntry->_video;
+ const Graphics::Surface *frame = video->decodeNextFrame();
+
+ if (!frame || !videoEntry->isEnabled()) {
+ return false;
+ }
+
+ Graphics::Surface *convertedFrame = 0;
+ Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
+
+ if (frame->format != pixelFormat) {
+ // We don't support downconverting to 8bpp without having
+ // support in the codec. Set _enableDither if shows up.
+ if (pixelFormat.bytesPerPixel == 1) {
+ warning("Cannot convert high color video frame to 8bpp");
+ return false;
+ }
+
+ // Convert to the current screen format
+ convertedFrame = frame->convertTo(pixelFormat, video->getPalette());
+ frame = convertedFrame;
+ } else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) {
+ // Set the palette when running in 8bpp mode only
+ // Don't do this for Myst, which has its own per-stack handling
+ if (_vm->getGameType() != GType_MYST)
+ _vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256);
+ }
+
+ // Clip the video to make sure it stays on the screen (Myst does this a few times)
+ Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight());
+ targetRect.translate(videoEntry->getX(), videoEntry->getY());
+
+ Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight());
+
+ if (targetRect.left < 0) {
+ frameRect.left -= targetRect.left;
+ targetRect.left = 0;
+ }
+
+ if (targetRect.top < 0) {
+ frameRect.top -= targetRect.top;
+ targetRect.top = 0;
+ }
+
+ if (targetRect.right > _vm->_system->getWidth()) {
+ frameRect.right -= targetRect.right - _vm->_system->getWidth();
+ targetRect.right = _vm->_system->getWidth();
+ }
+
+ if (targetRect.bottom > _vm->_system->getHeight()) {
+ frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight();
+ targetRect.bottom = _vm->_system->getHeight();
+ }
+
+ _vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch,
+ targetRect.left, targetRect.top, targetRect.width(), targetRect.height());
+
+ // Delete 8bpp conversion surface
+ if (convertedFrame) {
+ convertedFrame->free();
+ delete convertedFrame;
+ }
+
+ // We've drawn something to the screen, make sure we update it
+ return true;
+}
+
void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
Common::SeekableReadStream *mlstStream = _vm->getResource(ID_MLST, card);
uint16 recordCount = mlstStream->readUint16BE();
@@ -582,11 +589,9 @@ bool VideoManager::isVideoPlaying() {
}
void VideoManager::drawVideoFrame(VideoHandle handle, const Audio::Timestamp &time) {
- // FIXME: This should be done separately from the "playing"
- // videos eventually.
assert(handle);
handle->seek(time);
- updateMovies();
+ drawNextFrame(handle._ptr);
handle->stop();
}
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index c5a3dc7041..d0edab9def 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -350,6 +350,8 @@ private:
VideoList::iterator findEntry(VideoEntryPtr ptr);
void removeEntry(VideoEntryPtr ptr);
+ bool drawNextFrame(VideoEntryPtr videoEntry);
+
// Dithering control
bool _enableDither;
void checkEnableDither(VideoEntryPtr &entry);
diff --git a/engines/mohawk/view.cpp b/engines/mohawk/view.cpp
index 1aaf32ea78..70d20270a5 100644
--- a/engines/mohawk/view.cpp
+++ b/engines/mohawk/view.cpp
@@ -37,6 +37,23 @@ Module::~Module() {
}
Feature::Feature(View *view) : _view(view) {
+ _next = _prev = nullptr;
+ _drawProc = nullptr;
+ _moveProc = nullptr;
+ _doneProc = nullptr;
+ _frameProc = nullptr;
+ _timeProc = nullptr;
+ _region = 0;
+ _id = 0;
+ _scrbId = 0;
+ _storedScrbId = 0;
+ _flags = 0;
+ _nextTime = 0;
+ _delayTime = 0;
+ _dirty = false;
+ _needsReset = false;
+ _justReset = false;
+ _done = false;
}
Feature::~Feature() {
@@ -75,11 +92,10 @@ void Feature::setNodeDefaults(Feature *prev, Feature *next) {
_flags = 0;
- _dirty = 1;
- _needsReset = 1;
- _justReset = 0; // old
- _notifyDone = 0;
- _done = 0; // new
+ _dirty = true;
+ _needsReset = true;
+ _justReset = false; // old
+ _done = false; // new
_nextTime = 0;
_delayTime = 0;
@@ -107,11 +123,11 @@ void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
resetFrame();
_nextTime = 0; // New feature code uses _view->_lastIdleTime, but should be equivalent.
_data.enabled = enabled;
- _dirty = 1;
+ _dirty = true;
finishResetFeatureScript();
- _needsReset = 0;
+ _needsReset = false;
if (_region) {
// TODO: mark _region as dirty
@@ -123,7 +139,6 @@ void Feature::resetFeatureScript(uint16 enabled, uint16 scrbId) {
void Feature::resetFeature(bool notifyDone, Module::FeatureProc doneProc, uint16 scrbId) {
resetFeatureScript(1, scrbId);
_doneProc = doneProc;
- _notifyDone = notifyDone;
}
void Feature::hide(bool clip) {
@@ -159,7 +174,7 @@ void Feature::moveAndUpdate(Common::Point newPos) {
return;
_nextTime = 0;
- _dirty = 1;
+ _dirty = true;
// TODO: mark _data.bounds as dirty
if (_data.bitmapIds[0])
@@ -228,7 +243,7 @@ void OldFeature::resetScript() {
}
void OldFeature::finishResetFeatureScript() {
- _justReset = 1;
+ _justReset = true;
if (_flags & kFeatureOldAdjustByPos) {
Common::SeekableReadStream *ourSCRB = _view->getSCRB(_data.scrbIndex, _scrbId);
@@ -240,6 +255,13 @@ void OldFeature::finishResetFeatureScript() {
}
NewFeature::NewFeature(View *view) : Feature(view) {
+ _unknown168 = 0;
+ _pickupProc = nullptr;
+ _dropProc = nullptr;
+ _dragMoveProc = nullptr;
+ _oldMoveProc = nullptr;
+ _dragFlags = 0;
+ _oldFlags = 0;
}
NewFeature::~NewFeature() {
@@ -307,7 +329,7 @@ void NewFeature::resetScript() {
}
void NewFeature::finishResetFeatureScript() {
- _done = 0;
+ _done = false;
}
View::View(MohawkEngine *vm) : _vm(vm) {
@@ -319,6 +341,12 @@ View::View(MohawkEngine *vm) : _vm(vm) {
_compoundSHAPGroups[i] = 0;
}
_numSCRBGroups = 0;
+
+ _lastIdleTime = 0;
+ _needsUpdate = false;
+ _gfx = nullptr;
+ _rootNode = nullptr;
+ _cursorNode = nullptr;
}
View::~View() {
@@ -347,7 +375,7 @@ void View::idleView() {
}
if (node->_drawProc)
(_currentModule->*(node->_drawProc))(node);
- node->_dirty = 0;
+ node->_dirty = false;
}
if (_needsUpdate) {
diff --git a/engines/mohawk/view.h b/engines/mohawk/view.h
index 47853f056f..463715b765 100644
--- a/engines/mohawk/view.h
+++ b/engines/mohawk/view.h
@@ -138,11 +138,10 @@ public:
uint32 _flags;
uint32 _nextTime;
uint32 _delayTime;
- uint16 _dirty; // byte in old
- byte _needsReset;
- byte _justReset; // old
- byte _notifyDone; // old
- byte _done; // new
+ bool _dirty; // byte in old
+ bool _needsReset;
+ bool _justReset; // old
+ bool _done; // new
FeatureData _data;
@@ -192,13 +191,6 @@ protected:
void finishResetFeatureScript();
};
-#define NUM_SYNC_CHANNELS 17
-struct SyncChannel {
- uint16 masterId;
- byte state;
- bool alternate;
-};
-
class View {
public:
View(MohawkEngine *vm);
@@ -234,7 +226,6 @@ public:
void sortView();
uint32 _lastIdleTime;
- SyncChannel _syncChannels[NUM_SYNC_CHANNELS];
virtual uint32 getTime() = 0;
diff --git a/engines/mortevielle/configure.engine b/engines/mortevielle/configure.engine
index a7fb2ccda6..0fe89acc99 100644
--- a/engines/mortevielle/configure.engine
+++ b/engines/mortevielle/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine mortevielle "Mortevielle" yes
+add_engine mortevielle "Mortevielle" yes "" "" "highres"
diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp
index b6c27e6b12..6791707dd5 100644
--- a/engines/mortevielle/detection.cpp
+++ b/engines/mortevielle/detection.cpp
@@ -55,7 +55,7 @@ public:
MortevielleMetaEngine() : AdvancedMetaEngine(Mortevielle::MortevielleGameDescriptions, sizeof(Mortevielle::MortevielleGameDescription),
MortevielleGame) {
_md5Bytes = 512;
- _singleid = "mortevielle";
+ _singleId = "mortevielle";
// Use kADFlagUseExtraAsHint to distinguish between original and improved versions
// (i.e. use or not of the game data file).
_flags = kADFlagUseExtraAsHint;
diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp
index 90d366ed7e..81b2edb57d 100644
--- a/engines/mortevielle/mortevielle.cpp
+++ b/engines/mortevielle/mortevielle.cpp
@@ -145,6 +145,7 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr
_endGame = false;
_loseGame = false;
_txxFileFl = false;
+ _is = 0;
}
MortevielleEngine::~MortevielleEngine() {
diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp
index 9f46940e1f..3065d6c551 100644
--- a/engines/mortevielle/saveload.cpp
+++ b/engines/mortevielle/saveload.cpp
@@ -237,7 +237,7 @@ bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader
SaveStateList SavegameManager::listSaves(const Common::String &target) {
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern);
sort(files.begin(), files.end()); // Sort (hopefully ensuring we are sorted numerically..)
diff --git a/engines/mortevielle/sound.cpp b/engines/mortevielle/sound.cpp
index f02ccb69ea..77eba4cd6d 100644
--- a/engines/mortevielle/sound.cpp
+++ b/engines/mortevielle/sound.cpp
@@ -28,6 +28,7 @@
#include "mortevielle/mortevielle.h"
#include "mortevielle/sound.h"
+#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "common/scummsys.h"
diff --git a/engines/mortevielle/sound.h b/engines/mortevielle/sound.h
index d913684935..15b4667afa 100644
--- a/engines/mortevielle/sound.h
+++ b/engines/mortevielle/sound.h
@@ -28,11 +28,14 @@
#ifndef MORTEVIELLE_SOUND_H
#define MORTEVIELLE_SOUND_H
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/mutex.h"
#include "common/queue.h"
+namespace Audio {
+class QueuingAudioStream;
+}
+
namespace Mortevielle {
class MortevielleEngine;
diff --git a/engines/neverhood/configure.engine b/engines/neverhood/configure.engine
index 46910e293e..f04e6c69f6 100644
--- a/engines/neverhood/configure.engine
+++ b/engines/neverhood/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine neverhood "Neverhood" yes
+add_engine neverhood "Neverhood" yes "" "" "highres"
diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp
index c663d5d3a4..0f409a6435 100644
--- a/engines/neverhood/detection.cpp
+++ b/engines/neverhood/detection.cpp
@@ -41,7 +41,7 @@ struct NeverhoodGameDescription {
};
const char *NeverhoodEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 NeverhoodEngine::getFeatures() const {
@@ -114,6 +114,23 @@ static const NeverhoodGameDescription gameDescriptions[] = {
},
{
+ // Neverhood earlier English demo version
+ {
+ "neverhood",
+ "Demo",
+ AD_ENTRY1s("nevdemo.blb", "9cbc33bc8ebacacfc8071f3e26a9c85f", 22357020),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ },
+
+ {
// Neverhood Russian version. Dyadyushka Risech
{
"neverhood",
@@ -181,8 +198,8 @@ static const ExtraGuiOption neverhoodExtraGuiOption3 = {
class NeverhoodMetaEngine : public AdvancedMetaEngine {
public:
NeverhoodMetaEngine() : AdvancedMetaEngine(Neverhood::gameDescriptions, sizeof(Neverhood::NeverhoodGameDescription), neverhoodGames) {
- _singleid = "neverhood";
- _guioptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI);
+ _singleId = "neverhood";
+ _guiOptions = GUIO2(GUIO_NOSUBTITLES, GUIO_NOMIDI);
}
virtual const char *getName() const {
diff --git a/engines/neverhood/diskplayerscene.cpp b/engines/neverhood/diskplayerscene.cpp
index 96a935851c..e79f4c9d77 100644
--- a/engines/neverhood/diskplayerscene.cpp
+++ b/engines/neverhood/diskplayerscene.cpp
@@ -22,6 +22,7 @@
#include "neverhood/diskplayerscene.h"
#include "neverhood/mouse.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/diskplayerscene.h b/engines/neverhood/diskplayerscene.h
index 2ae85b9a0b..dba10f3a46 100644
--- a/engines/neverhood/diskplayerscene.h
+++ b/engines/neverhood/diskplayerscene.h
@@ -26,11 +26,11 @@
#include "neverhood/neverhood.h"
#include "neverhood/resourceman.h"
#include "neverhood/scene.h"
-#include "neverhood/smackerplayer.h"
namespace Neverhood {
class DiskplayerScene;
+class SmackerPlayer;
class AsDiskplayerSceneKey : public AnimatedSprite {
public:
diff --git a/engines/neverhood/menumodule.cpp b/engines/neverhood/menumodule.cpp
index 826f175d47..e58dd31f03 100644
--- a/engines/neverhood/menumodule.cpp
+++ b/engines/neverhood/menumodule.cpp
@@ -23,6 +23,8 @@
#include "common/config-manager.h"
#include "common/translation.h"
+#include "audio/mixer.h"
+
#include "gui/saveload.h"
#include "neverhood/menumodule.h"
@@ -609,7 +611,8 @@ void TextEditWidget::onClick() {
++newCursorPos;
_cursorPos = MIN((int)_entryString.size(), newCursorPos);
}
- _cursorSurface->setVisible(true);
+ if (!_readOnly)
+ _cursorSurface->setVisible(true);
refresh();
}
Widget::onClick();
@@ -1058,7 +1061,7 @@ static const NRect kSaveGameMenuTextEditRect = { 0, 0, 377, 17 };
static const NRect kSaveGameMenuMouseRect = { 50, 47, 427, 64 };
SaveGameMenu::SaveGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList)
- : GameStateMenu(vm, parentModule, savegameList, kSaveGameMenuButtonFileHashes, kSaveGameMenuButtonCollisionBounds,
+ : GameStateMenu(vm, parentModule, savegameList, kSaveGameMenuButtonFileHashes, kSaveGameMenuButtonCollisionBounds,
0x30084E25, 0x2328121A,
0x84E21308, &kSaveGameMenuMouseRect,
0x1115A223, 60, 142, kSaveGameMenuListBoxRect,
@@ -1068,9 +1071,11 @@ SaveGameMenu::SaveGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameLi
}
void SaveGameMenu::performAction() {
- ((MenuModule*)_parentModule)->setSavegameInfo(_textEditWidget->getString(),
- _listBox->getCurrIndex(), _textEditWidget->isModified());
- leaveScene(0);
+ if (!_textEditWidget->getString().empty()) {
+ ((MenuModule*)_parentModule)->setSavegameInfo(_textEditWidget->getString(),
+ _listBox->getCurrIndex(), _textEditWidget->isModified());
+ leaveScene(0);
+ }
}
static const uint32 kLoadGameMenuButtonFileHashes[] = {
@@ -1089,12 +1094,21 @@ static const NRect kLoadGameMenuButtonCollisionBounds[] = {
static const NRect kLoadGameMenuListBoxRect = { 0, 0, 320, 272 };
static const NRect kLoadGameMenuTextEditRect = { 0, 0, 320, 17 };
+
+#if 0
+// Unlike the original game, the text widget in our load dialog is read-only so
+// don't change the mouse cursor to indicate that you can type the name of the
+// game to load.
+//
+// Since we allow multiple saved games to have the same name, it's probably
+// better this way.
static const NRect kLoadGameMenuMouseRect = { 263, 48, 583, 65 };
+#endif
LoadGameMenu::LoadGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameList *savegameList)
: GameStateMenu(vm, parentModule, savegameList, kLoadGameMenuButtonFileHashes, kLoadGameMenuButtonCollisionBounds,
0x98620234, 0x201C2474,
- 0x2023098E, &kLoadGameMenuMouseRect,
+ 0x2023098E, NULL /* &kLoadGameMenuMouseRect */,
0x04040409, 263, 142, kLoadGameMenuListBoxRect,
0x10924C03, 0, 263, 48, kLoadGameMenuTextEditRect,
0x0BC600A3, 0x0F960021) {
@@ -1102,8 +1116,11 @@ LoadGameMenu::LoadGameMenu(NeverhoodEngine *vm, Module *parentModule, SavegameLi
}
void LoadGameMenu::performAction() {
- ((MenuModule*)_parentModule)->setLoadgameInfo(_listBox->getCurrIndex());
- leaveScene(0);
+ // TODO: The original would display a message here if nothing was selected.
+ if (!_textEditWidget->getString().empty()) {
+ ((MenuModule*)_parentModule)->setLoadgameInfo(_listBox->getCurrIndex());
+ leaveScene(0);
+ }
}
static const uint32 kDeleteGameMenuButtonFileHashes[] = {
@@ -1134,8 +1151,11 @@ DeleteGameMenu::DeleteGameMenu(NeverhoodEngine *vm, Module *parentModule, Savega
}
void DeleteGameMenu::performAction() {
- ((MenuModule*)_parentModule)->setDeletegameInfo(_listBox->getCurrIndex());
- leaveScene(0);
+ // TODO: The original would display a message here if no game was selected.
+ if (!_textEditWidget->getString().empty()) {
+ ((MenuModule*)_parentModule)->setDeletegameInfo(_listBox->getCurrIndex());
+ leaveScene(0);
+ }
}
QueryOverwriteMenu::QueryOverwriteMenu(NeverhoodEngine *vm, Module *parentModule, const Common::String &description)
diff --git a/engines/neverhood/modules/module1300.cpp b/engines/neverhood/modules/module1300.cpp
index 60ff0411a6..65bd353576 100644
--- a/engines/neverhood/modules/module1300.cpp
+++ b/engines/neverhood/modules/module1300.cpp
@@ -23,6 +23,7 @@
#include "neverhood/diskplayerscene.h"
#include "neverhood/gamemodule.h"
#include "neverhood/menumodule.h"
+#include "neverhood/smackerplayer.h"
#include "neverhood/modules/module1000_sprites.h"
#include "neverhood/modules/module1200_sprites.h"
#include "neverhood/modules/module1300.h"
diff --git a/engines/neverhood/modules/module1300.h b/engines/neverhood/modules/module1300.h
index 4a0ca6c062..8164a51d0d 100644
--- a/engines/neverhood/modules/module1300.h
+++ b/engines/neverhood/modules/module1300.h
@@ -26,10 +26,11 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
-#include "neverhood/smackerplayer.h"
namespace Neverhood {
+class SmackerPlayer;
+
class Module1300 : public Module {
public:
Module1300(NeverhoodEngine *vm, Module *parentModule, int which);
diff --git a/engines/neverhood/modules/module1300_sprites.h b/engines/neverhood/modules/module1300_sprites.h
index 6f4faaa234..bf9f72a5a7 100644
--- a/engines/neverhood/modules/module1300_sprites.h
+++ b/engines/neverhood/modules/module1300_sprites.h
@@ -26,7 +26,6 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
-#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/modules/module2800.cpp b/engines/neverhood/modules/module2800.cpp
index ab22390c7d..63d507d8fd 100644
--- a/engines/neverhood/modules/module2800.cpp
+++ b/engines/neverhood/modules/module2800.cpp
@@ -23,6 +23,7 @@
#include "neverhood/diskplayerscene.h"
#include "neverhood/gamemodule.h"
#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
#include "neverhood/modules/module1000_sprites.h"
#include "neverhood/modules/module1200_sprites.h"
#include "neverhood/modules/module1700_sprites.h"
diff --git a/engines/neverhood/navigationscene.h b/engines/neverhood/navigationscene.h
index 8e286effb9..e1dabfea3d 100644
--- a/engines/neverhood/navigationscene.h
+++ b/engines/neverhood/navigationscene.h
@@ -26,6 +26,7 @@
#include "neverhood/neverhood.h"
#include "neverhood/resourceman.h"
#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp
index c6cff86c72..0dc271997b 100644
--- a/engines/neverhood/neverhood.cpp
+++ b/engines/neverhood/neverhood.cpp
@@ -24,6 +24,8 @@
#include "common/config-manager.h"
#include "common/textconsole.h"
+#include "audio/mixer.h"
+
#include "base/plugins.h"
#include "base/version.h"
diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h
index 0661bcba0e..4c5f9c3303 100644
--- a/engines/neverhood/neverhood.h
+++ b/engines/neverhood/neverhood.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef NEVERHOOD_H
-#define NEVERHOOD_H
+#ifndef NEVERHOOD_NEVERHOOD_H
+#define NEVERHOOD_NEVERHOOD_H
#include "common/scummsys.h"
#include "common/events.h"
@@ -30,7 +30,6 @@
#include "common/savefile.h"
#include "common/str-array.h"
#include "common/system.h"
-#include "audio/mixer.h"
#include "engines/engine.h"
#include "gui/debugger.h"
#include "neverhood/console.h"
@@ -150,4 +149,4 @@ private:
} // End of namespace Neverhood
-#endif /* NEVERHOOD_H */
+#endif /* NEVERHOOD_NEVERHOOD_H */
diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp
index 1a8e74da38..8ed988c0fc 100644
--- a/engines/neverhood/scene.cpp
+++ b/engines/neverhood/scene.cpp
@@ -22,6 +22,7 @@
#include "neverhood/console.h"
#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/scene.h b/engines/neverhood/scene.h
index 98a7fa5090..1d1faf28bc 100644
--- a/engines/neverhood/scene.h
+++ b/engines/neverhood/scene.h
@@ -31,13 +31,13 @@
#include "neverhood/klaymen.h"
#include "neverhood/module.h"
#include "neverhood/palette.h"
-#include "neverhood/smackerplayer.h"
#include "neverhood/sprite.h"
#include "neverhood/staticdata.h"
namespace Neverhood {
class Console;
+class SmackerPlayer;
class Scene : public Entity {
public:
diff --git a/engines/neverhood/screen.cpp b/engines/neverhood/screen.cpp
index cc735c4c16..5cc7998210 100644
--- a/engines/neverhood/screen.cpp
+++ b/engines/neverhood/screen.cpp
@@ -21,6 +21,7 @@
*/
#include "graphics/palette.h"
+#include "video/smk_decoder.h"
#include "neverhood/screen.h"
namespace Neverhood {
diff --git a/engines/neverhood/screen.h b/engines/neverhood/screen.h
index 82ce90b245..91bbe12c66 100644
--- a/engines/neverhood/screen.h
+++ b/engines/neverhood/screen.h
@@ -25,11 +25,14 @@
#include "common/array.h"
#include "graphics/surface.h"
-#include "video/smk_decoder.h"
#include "neverhood/neverhood.h"
#include "neverhood/microtiles.h"
#include "neverhood/graphics.h"
+namespace Video {
+ class SmackerDecoder;
+}
+
namespace Neverhood {
struct RenderItem {
diff --git a/engines/neverhood/smackerscene.cpp b/engines/neverhood/smackerscene.cpp
index 2b43579130..50677d7d5c 100644
--- a/engines/neverhood/smackerscene.cpp
+++ b/engines/neverhood/smackerscene.cpp
@@ -21,6 +21,7 @@
*/
#include "neverhood/smackerscene.h"
+#include "neverhood/smackerplayer.h"
namespace Neverhood {
diff --git a/engines/neverhood/sound.cpp b/engines/neverhood/sound.cpp
index b15bea4a64..db22b72289 100644
--- a/engines/neverhood/sound.cpp
+++ b/engines/neverhood/sound.cpp
@@ -21,10 +21,17 @@
*/
#include "common/memstream.h"
-#include "graphics/palette.h"
+#include "audio/mixer.h"
#include "neverhood/sound.h"
+#include "neverhood/resource.h"
#include "neverhood/resourceman.h"
+// Convert volume from percent to 0..255
+#define VOLUME(volume) (Audio::Mixer::kMaxChannelVolume / 100 * (volume))
+
+// Convert panning from percent (50% equals center) to -127..0..+127
+#define PANNING(panning) (254 / 100 * (panning) - 127)
+
namespace Neverhood {
SoundResource::SoundResource(NeverhoodEngine *vm)
@@ -583,6 +590,11 @@ AudioResourceManSoundItem::AudioResourceManSoundItem(NeverhoodEngine *vm, uint32
_volume(100), _panning(50) {
_vm->_res->queryResource(_fileHash, _resourceHandle);
+ _soundHandle = new Audio::SoundHandle();
+}
+
+AudioResourceManSoundItem::~AudioResourceManSoundItem() {
+ delete _soundHandle;
}
void AudioResourceManSoundItem::loadSound() {
@@ -594,22 +606,22 @@ void AudioResourceManSoundItem::loadSound() {
}
void AudioResourceManSoundItem::unloadSound() {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->stopHandle(_soundHandle);
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->stopHandle(*_soundHandle);
_vm->_res->unloadResource(_resourceHandle);
_data = NULL;
}
void AudioResourceManSoundItem::setVolume(int16 volume) {
_volume = MIN<int16>(volume, 100);
- if (_isPlaying && _vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_volume));
+ if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_volume));
}
void AudioResourceManSoundItem::setPan(int16 pan) {
_panning = MIN<int16>(pan, 100);
- if (_isPlaying && _vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->setChannelVolume(_soundHandle, PANNING(_panning));
+ if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->setChannelVolume(*_soundHandle, PANNING(_panning));
}
void AudioResourceManSoundItem::playSound(bool looping) {
@@ -619,7 +631,7 @@ void AudioResourceManSoundItem::playSound(bool looping) {
const byte *shiftValue = _resourceHandle.extData();
Common::MemoryReadStream *stream = new Common::MemoryReadStream(_data, _resourceHandle.size(), DisposeAfterUse::NO);
NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, looping, DisposeAfterUse::YES, stream);
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle,
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _soundHandle,
audioStream, -1, VOLUME(_volume), PANNING(_panning));
debug(1, "playing sound %08X", _fileHash);
_isPlaying = true;
@@ -627,13 +639,13 @@ void AudioResourceManSoundItem::playSound(bool looping) {
}
void AudioResourceManSoundItem::stopSound() {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->stopHandle(_soundHandle);
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->stopHandle(*_soundHandle);
_isPlaying = false;
}
bool AudioResourceManSoundItem::isPlaying() {
- return _vm->_mixer->isSoundHandleActive(_soundHandle);
+ return _vm->_mixer->isSoundHandleActive(*_soundHandle);
}
AudioResourceManMusicItem::AudioResourceManMusicItem(NeverhoodEngine *vm, uint32 fileHash)
@@ -641,6 +653,11 @@ AudioResourceManMusicItem::AudioResourceManMusicItem(NeverhoodEngine *vm, uint32
_volume(100), _panning(50), _start(false), _isFadingIn(false), _isFadingOut(false), _isPlaying(false),
_fadeVolume(0), _fadeVolumeStep(0) {
+ _soundHandle = new Audio::SoundHandle();
+}
+
+AudioResourceManMusicItem::~AudioResourceManMusicItem() {
+ delete _soundHandle;
}
void AudioResourceManMusicItem::playMusic(int16 fadeVolumeStep) {
@@ -658,7 +675,7 @@ void AudioResourceManMusicItem::playMusic(int16 fadeVolumeStep) {
}
void AudioResourceManMusicItem::stopMusic(int16 fadeVolumeStep) {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle)) {
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
if (fadeVolumeStep != 0) {
if (_isFadingIn)
_isFadingIn = false;
@@ -667,7 +684,7 @@ void AudioResourceManMusicItem::stopMusic(int16 fadeVolumeStep) {
_isFadingOut = true;
_fadeVolumeStep = fadeVolumeStep;
} else {
- _vm->_mixer->stopHandle(_soundHandle);
+ _vm->_mixer->stopHandle(*_soundHandle);
}
_isPlaying = false;
}
@@ -677,8 +694,8 @@ void AudioResourceManMusicItem::unloadMusic() {
if (_isFadingOut) {
_canRestart = true;
} else {
- if (_vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->stopHandle(_soundHandle);
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->stopHandle(*_soundHandle);
_isPlaying = false;
_terminate = true;
}
@@ -686,8 +703,8 @@ void AudioResourceManMusicItem::unloadMusic() {
void AudioResourceManMusicItem::setVolume(int16 volume) {
_volume = MIN<int16>(volume, 100);
- if (_isPlaying && _vm->_mixer->isSoundHandleActive(_soundHandle))
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_volume));
+ if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_volume));
}
void AudioResourceManMusicItem::restart() {
@@ -698,33 +715,33 @@ void AudioResourceManMusicItem::restart() {
void AudioResourceManMusicItem::update() {
- if (_start && !_vm->_mixer->isSoundHandleActive(_soundHandle)) {
+ if (_start && !_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
ResourceHandle resourceHandle;
_vm->_res->queryResource(_fileHash, resourceHandle);
Common::SeekableReadStream *stream = _vm->_res->createStream(_fileHash);
const byte *shiftValue = resourceHandle.extData();
NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, true, DisposeAfterUse::YES, stream);
- _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle,
+ _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle,
audioStream, -1, VOLUME(_isFadingIn ? _fadeVolume : _volume),
PANNING(_panning));
_start = false;
_isPlaying = true;
}
- if (_vm->_mixer->isSoundHandleActive(_soundHandle)) {
+ if (_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
if (_isFadingIn) {
_fadeVolume += _fadeVolumeStep;
if (_fadeVolume >= _volume) {
_fadeVolume = _volume;
_isFadingIn = false;
}
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_fadeVolume));
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_fadeVolume));
}
if (_isFadingOut) {
_fadeVolume -= _fadeVolumeStep;
if (_fadeVolume < 0)
_fadeVolume = 0;
- _vm->_mixer->setChannelVolume(_soundHandle, VOLUME(_fadeVolume));
+ _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_fadeVolume));
if (_fadeVolume == 0) {
_isFadingOut = false;
stopMusic(0);
diff --git a/engines/neverhood/sound.h b/engines/neverhood/sound.h
index 512b0fef98..e5e4ec9216 100644
--- a/engines/neverhood/sound.h
+++ b/engines/neverhood/sound.h
@@ -25,21 +25,21 @@
#include "audio/audiostream.h"
#include "common/array.h"
-#include "graphics/surface.h"
-#include "neverhood/neverhood.h"
-#include "neverhood/resource.h"
+#include "neverhood/resourceman.h"
-namespace Neverhood {
+namespace Common {
+class SeekableReadStream;
+}
-// Convert volume from percent to 0..255
-#define VOLUME(volume) (Audio::Mixer::kMaxChannelVolume / 100 * (volume))
+namespace Audio {
+class SoundHandle;
+}
-// Convert panning from percent (50% equals center) to -127..0..+127
-#define PANNING(panning) (254 / 100 * (panning) - 127)
+namespace Neverhood {
+class NeverhoodEngine;
class AudioResourceManSoundItem;
class AudioResourceManMusicItem;
-class AudioResourceMan;
class SoundResource {
public:
@@ -213,6 +213,7 @@ private:
class AudioResourceManSoundItem {
public:
AudioResourceManSoundItem(NeverhoodEngine *vm, uint32 fileHash);
+ ~AudioResourceManSoundItem();
void loadSound();
void unloadSound();
void setVolume(int16 volume);
@@ -229,12 +230,13 @@ protected:
bool _isPlaying;
int16 _volume;
int16 _panning;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
};
class AudioResourceManMusicItem {
public:
AudioResourceManMusicItem(NeverhoodEngine *vm, uint32 fileHash);
+ ~AudioResourceManMusicItem();
void playMusic(int16 fadeVolumeStep);
void stopMusic(int16 fadeVolumeStep);
void unloadMusic();
@@ -258,7 +260,7 @@ protected:
bool _isFadingOut;
int16 _fadeVolume;
int16 _fadeVolumeStep;
- Audio::SoundHandle _soundHandle;
+ Audio::SoundHandle *_soundHandle;
};
class AudioResourceMan {
diff --git a/engines/parallaction/adlib.cpp b/engines/parallaction/adlib.cpp
index 568ad190aa..a981a5553b 100644
--- a/engines/parallaction/adlib.cpp
+++ b/engines/parallaction/adlib.cpp
@@ -277,6 +277,15 @@ public:
_channels[i].init(this, i);
_isOpen = false;
+
+ _opl = NULL;
+ memset(_voices, 0, sizeof(_voices));
+
+ _lastVoice = 0;
+ _percussionMask = 0;
+
+ _adlibTimerProc = NULL;
+ _adlibTimerParam = NULL;
}
int open();
diff --git a/engines/parallaction/balloons.cpp b/engines/parallaction/balloons.cpp
index 234abff59a..c0a516eb0f 100644
--- a/engines/parallaction/balloons.cpp
+++ b/engines/parallaction/balloons.cpp
@@ -55,7 +55,7 @@ protected:
}
public:
- WrappedLineFormatter(Font *font) : _font(font) { }
+ WrappedLineFormatter(Font *font) : _font(font), _lines(0), _lineWidth(0) { }
virtual ~WrappedLineFormatter() { }
virtual void calc(const Common::String &text, uint16 maxwidth) {
@@ -136,7 +136,7 @@ protected:
}
public:
- StringExtent_NS(Font *font) : WrappedLineFormatter(font) { }
+ StringExtent_NS(Font *font) : WrappedLineFormatter(font), _width(0), _height(0) { }
uint width() const { return _width; }
uint height() const { return _height; }
@@ -189,7 +189,8 @@ protected:
}
public:
- StringWriter_NS(Parallaction_ns *vm, Font *font) : WrappedLineFormatter(font), _vm(vm) { }
+ StringWriter_NS(Parallaction_ns *vm, Font *font) : WrappedLineFormatter(font), _vm(vm),
+ _width(0), _height(0), _color(0), _surf(NULL) { }
void write(const Common::String &text, uint maxWidth, byte color, Graphics::Surface *surf) {
StringExtent_NS se(_font);
@@ -464,7 +465,7 @@ protected:
}
public:
- StringExtent_BR(Font *font) : WrappedLineFormatter(font) { }
+ StringExtent_BR(Font *font) : WrappedLineFormatter(font), _width(0), _height(0) { }
uint width() const { return _width; }
uint height() const { return _height; }
@@ -480,7 +481,8 @@ class StringWriter_BR : public WrappedLineFormatter {
Graphics::Surface *_surf;
protected:
- StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font) {
+ StringWriter_BR(Font *font, byte color) : WrappedLineFormatter(font), _width(0), _height(0),
+ _color(color), _x(0), _y(0), _surf(NULL) {
}
@@ -504,7 +506,8 @@ protected:
}
public:
- StringWriter_BR(Font *font) : WrappedLineFormatter(font) { }
+ StringWriter_BR(Font *font) : WrappedLineFormatter(font), _width(0), _height(0),
+ _color(0), _x(0), _y(0), _surf(NULL) { }
void write(const Common::String &text, uint maxWidth, byte color, Graphics::Surface *surf) {
StringExtent_BR se(_font);
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index a7087c64d7..0bf2babb5b 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -32,6 +32,7 @@ namespace Parallaction {
Debugger::Debugger(Parallaction *vm)
: GUI::Debugger() {
_vm = vm;
+ _mouseState = MOUSE_ENABLED_SHOW;
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
registerCmd("location", WRAP_METHOD(Debugger, Cmd_Location));
diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp
index 0c7ebb2b05..4c52990874 100644
--- a/engines/parallaction/detection.cpp
+++ b/engines/parallaction/detection.cpp
@@ -220,7 +220,7 @@ static const PARALLACTIONGameDescription gameDescriptions[] = {
class ParallactionMetaEngine : public AdvancedMetaEngine {
public:
ParallactionMetaEngine() : AdvancedMetaEngine(Parallaction::gameDescriptions, sizeof(Parallaction::PARALLACTIONGameDescription), parallactionGames) {
- _guioptions = GUIO1(GUIO_NOLAUNCHLOAD);
+ _guiOptions = GUIO1(GUIO_NOLAUNCHLOAD);
}
virtual const char *getName() const {
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 62e2152816..4dbedc8dbe 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -140,6 +140,21 @@ DialogueManager::DialogueManager(Parallaction *vm, ZonePtr z) : _vm(vm), _z(z) {
_cmdList = 0;
_answerId = 0;
+
+ _faceId = 0;
+
+ _q = NULL;
+ memset(_visAnswers, 0, sizeof(_visAnswers));
+ _numVisAnswers = 0;
+
+ _selection = _oldSelection = 0;
+
+ _isKeyDown = false;
+ _downKey = 0;
+
+ _mouseButtons = 0;
+
+ _state = DIALOGUE_START;
}
void DialogueManager::start() {
@@ -412,7 +427,8 @@ protected:
}
public:
- DialogueManager_ns(Parallaction_ns *vm, ZonePtr z) : DialogueManager(vm, z), _vm(vm) {
+ DialogueManager_ns(Parallaction_ns *vm, ZonePtr z) : DialogueManager(vm, z), _vm(vm),
+ _passwordChanged(false), _askPassword(false) {
_ballonPos._questionBalloon = Common::Point(140, 10);
_ballonPos._questionChar = Common::Point(190, 80);
_ballonPos._answerChar = Common::Point(10, 80);
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 7458065b8c..af2d2b82e0 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -762,14 +762,11 @@ Common::String AmigaDisk_br::selectArchive(const Common::String& name) {
}
-Disk_br::Disk_br(Parallaction *vm) : _vm(vm), _baseDir(0) {
-
+Disk_br::Disk_br(Parallaction *vm) : _vm(vm), _baseDir(0), _language(0) {
}
Disk_br::~Disk_br() {
_sset.clear();
}
-
-
} // namespace Parallaction
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index 28e61b04f9..c25236acbd 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -238,7 +238,7 @@ void Disk_ns::setLanguage(uint16 language) {
#pragma mark -
-DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm) {
+DosDisk_ns::DosDisk_ns(Parallaction* vm) : Disk_ns(vm), _gfx(NULL) {
}
diff --git a/engines/parallaction/exec.cpp b/engines/parallaction/exec.cpp
index ceba072173..3d4e9bd803 100644
--- a/engines/parallaction/exec.cpp
+++ b/engines/parallaction/exec.cpp
@@ -81,7 +81,7 @@ void ProgramExec::runScripts(ProgramList::iterator first, ProgramList::iterator
return;
}
-ProgramExec::ProgramExec() : _modCounter(0) {
+ProgramExec::ProgramExec() : _modCounter(0), _instructionNames(NULL) {
}
diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp
index 57b04deb12..0476b15971 100644
--- a/engines/parallaction/font.cpp
+++ b/engines/parallaction/font.cpp
@@ -70,6 +70,8 @@ public:
_data = (byte *)malloc(size);
stream.read(_data, size);
+ _cp = 0;
+ _bufPitch = 0;
}
~BraFont() {
@@ -302,7 +304,7 @@ protected:
}
public:
- DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width) {
+ DosFont(Cnv *cnv) : _data(cnv), _pitch(cnv->_width), _cp(NULL), _bufPitch(0) {
}
~DosFont() {
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index f1499f7782..819804bfe7 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -32,7 +32,8 @@ namespace Parallaction {
GfxObj::GfxObj(uint objType, Frames *frames, const char* name) :
_frames(frames), x(0), y(0), z(0), _prog(0), _flags(0),
- type(objType), frame(0), layer(3), scale(100), _hasMask(false), _hasPath(false) {
+ type(objType), frame(0), layer(3), scale(100), _hasMask(false), _hasPath(false),
+ transparentKey(0), _maskId(0), _pathId(0) {
if (name) {
_name = strdup(name);
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 06b315016a..162671b68a 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -743,6 +743,8 @@ Gfx::Gfx(Parallaction* vm) :
_nextProjectorPos = 0;
_hbCircleRadius = 0;
+ _overlayMode = false;
+
_unpackedBitmap = new byte[MAXIMUM_UNPACKED_BITMAP_SIZE];
assert(_unpackedBitmap);
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index 55e2bbca84..03b4dd97ef 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -57,7 +57,7 @@ protected:
public:
- Font() {}
+ Font() : _color(0) {}
virtual ~Font() {}
virtual void setColor(byte color) {
diff --git a/engines/parallaction/gui_br.cpp b/engines/parallaction/gui_br.cpp
index ae3d136b0e..17d759d26f 100644
--- a/engines/parallaction/gui_br.cpp
+++ b/engines/parallaction/gui_br.cpp
@@ -43,7 +43,8 @@ protected:
int _fadeSteps;
public:
- SplashInputState_BR(Parallaction *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),
+ _timeOut(0), _startTime(0), _fadeSteps(0) {
}
virtual MenuInputState* run() {
@@ -382,6 +383,9 @@ public:
_menuObj->getRect(0, _menuRect);
_cellW = _menuRect.width() / 3;
_cellH = _menuRect.height() / 2;
+
+ _menuObjId = _mscMenuObjId = _sfxMenuObjId = 0;
+ _sfxStatus = _mscStatus = 0;
}
~IngameMenuInputState_BR() {
diff --git a/engines/parallaction/gui_ns.cpp b/engines/parallaction/gui_ns.cpp
index 3d977c9e51..3c312c4f2d 100644
--- a/engines/parallaction/gui_ns.cpp
+++ b/engines/parallaction/gui_ns.cpp
@@ -43,7 +43,8 @@ protected:
Parallaction *_vm;
public:
- SplashInputState_NS(Parallaction *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),
+ _timeOut(0), _startTime(0) {
}
virtual MenuInputState* run() {
@@ -298,7 +299,7 @@ class LoadGameInputState_NS : public MenuInputState {
Parallaction *_vm;
public:
- LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm) { }
+ LoadGameInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("loadgame", helper), _vm(vm), _result(false) { }
virtual MenuInputState* run() {
if (!_result) {
@@ -477,6 +478,11 @@ public:
_labels[0] = 0;
_labels[1] = 0;
+ _fail = false;
+ _len = 0;
+ _startTime = 0;
+ _state = 0;
+
_codeSelectBlocks[0] = Common::Rect( 111, 129, 127, 153 ); // na
_codeSelectBlocks[1] = Common::Rect( 128, 120, 144, 144 ); // wa
_codeSelectBlocks[2] = Common::Rect( 145, 111, 161, 135 ); // ra
@@ -689,6 +695,9 @@ public:
ShowCreditsInputState_NS(Parallaction *vm, MenuInputHelper *helper) : MenuInputState("showcredits", helper), _vm(vm) {
_labels[0] = 0;
_labels[1] = 0;
+
+ _current = 0;
+ _startTime = 0;
}
~ShowCreditsInputState_NS() {
@@ -827,6 +836,8 @@ public:
_labels[1] = 0;
_labels[2] = 0;
_labels[3] = 0;
+
+ _allPartsComplete = false;
}
void destroyLabels() {
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 290af339bb..c62e7479d3 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -70,10 +70,15 @@ Input::Input(Parallaction *vm) : _vm(vm) {
_mouseButtons = 0;
_delayedActionZone.reset();
+ _inputMode = 0;
+ _hasKeyPressEvent = false;
+
_dinoCursor = 0;
_dougCursor = 0;
_donnaCursor = 0;
_comboArrow = 0;
+ _mouseArrow = 0;
+
initCursors();
}
diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp
index 50a5b38d8d..950d62a841 100644
--- a/engines/parallaction/objects.cpp
+++ b/engines/parallaction/objects.cpp
@@ -145,6 +145,8 @@ Program::Program() {
_locals = new LocalVariable[NUM_LOCALS];
_numLocals = 0;
_status = kProgramIdle;
+ _ip = 0;
+ _loopStart = 0;
}
Program::~Program() {
@@ -163,7 +165,7 @@ int16 Program::findLocal(const char* name) {
int16 Program::addLocal(const char *name, int16 value, int16 min, int16 max) {
assert(_numLocals < NUM_LOCALS);
- strcpy(_localNames[_numLocals], name);
+ Common::strlcpy(_localNames[_numLocals], name, 10);
_locals[_numLocals].setRange(min, max);
_locals[_numLocals].setValue(value);
@@ -259,6 +261,8 @@ Answer::Answer() {
_noFlags = 0;
_yesFlags = 0;
_hasCounterCondition = false;
+ _counterValue = 0;
+ _counterOp = 0;
}
bool Answer::textIsNull() {
@@ -298,6 +302,7 @@ Instruction::Instruction() {
// common
_immediate = 0;
+ _endif = 0;
// BRA specific
_text = 0;
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index 2b75e78582..bbe759dffe 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -60,6 +60,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
DebugMan.addDebugChannel(kDebugMenu, "menu", "Menu debug level");
DebugMan.addDebugChannel(kDebugInventory, "inventory", "Inventory debug level");
+ _screenWidth = 0;
_screenHeight = 0;
_screenSize = 0;
_gameType = 0;
@@ -86,6 +87,7 @@ Parallaction::Parallaction(OSystem *syst, const PARALLACTIONGameDescription *gam
_inventory = 0;
_currentLocationIndex = 0;
_numLocations = 0;
+ _language = 0;
}
Parallaction::~Parallaction() {
@@ -208,7 +210,7 @@ void Parallaction::allocateLocationSlot(const char *name) {
error("No more location slots available. Please report this immediately to ScummVM team");
if (_currentLocationIndex == -1) {
- strcpy(_locationNames[_numLocations], name);
+ Common::strlcpy(_locationNames[_numLocations], name, 10);
_currentLocationIndex = _numLocations;
_numLocations++;
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 6ea50584f8..c4839897ef 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef PARALLACTION_H
-#define PARALLACTION_H
+#ifndef PARALLACTION_PARALLACTION_H
+#define PARALLACTION_PARALLACTION_H
#include "common/str.h"
#include "common/stack.h"
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 1e1c0b0a3d..9f045cb397 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -320,7 +320,7 @@ void Parallaction_br::changeLocation() {
freeLocation(false);
// load new location
- strcpy(_location._name, _newLocationName.c_str());
+ Common::strlcpy(_location._name, _newLocationName.c_str(), 100);
parseLocation(_location._name);
if (_location._startPosition.x != -1000) {
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index 144c2b3a98..ccf7130eb8 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -352,8 +352,8 @@ void Parallaction_ns::changeLocation() {
}
char location[200];
- strcpy(location, _newLocationName.c_str());
- strcpy(_location._name, _newLocationName.c_str());
+ Common::strlcpy(location, _newLocationName.c_str(), 200);
+ Common::strlcpy(_location._name, _newLocationName.c_str(), 100);
debugC(1, kDebugExec, "changeLocation(%s)", location);
@@ -395,7 +395,7 @@ void Parallaction_ns::changeLocation() {
changeCharacter(locname.character());
}
- strcpy(g_saveData1, locname.location());
+ Common::strlcpy(g_saveData1, locname.location(), 30);
parseLocation(g_saveData1);
if (_location._startPosition.x != -1000) {
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index c37cee692e..725a8b5996 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -226,6 +226,7 @@ uint16 Script::readLineToken(bool errorOnEOF) {
void Parser::reset() {
_currentOpcodes = 0;
_currentStatements = 0;
+ _lookup = 0;
_statements.clear();
_opcodes.clear();
diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h
index 7b77f58eb0..e7ae7dcc36 100644
--- a/engines/parallaction/parser.h
+++ b/engines/parallaction/parser.h
@@ -405,7 +405,7 @@ protected:
virtual void parseRValue(ScriptVar &var, const char *str);
public:
- ProgramParser_br(Parallaction_br *vm) : ProgramParser_ns((Parallaction_ns*)vm), _vm(vm) {
+ ProgramParser_br(Parallaction_br *vm) : ProgramParser_ns((Parallaction_ns*)vm), _vm(vm), _openIfStatement(0) {
}
virtual void init();
diff --git a/engines/parallaction/saveload.cpp b/engines/parallaction/saveload.cpp
index 6d598d9557..0f4ceae7a5 100644
--- a/engines/parallaction/saveload.cpp
+++ b/engines/parallaction/saveload.cpp
@@ -25,10 +25,7 @@
#include "common/textconsole.h"
#include "common/translation.h"
-#include "gui/dialog.h"
#include "gui/saveload.h"
-#include "gui/widget.h"
-#include "gui/widgets/list.h"
#include "gui/message.h"
#include "parallaction/parallaction.h"
@@ -96,7 +93,7 @@ void SaveLoad_ns::doLoadGame(uint16 slot) {
uint16 _si;
for (_si = 0; _si < _vm->_numLocations; _si++) {
s = f->readLine();
- strcpy(_vm->_locationNames[_si], s.c_str());
+ Common::strlcpy(_vm->_locationNames[_si], s.c_str(), 32);
s = f->readLine();
_vm->_localFlags[_si] = atoi(s.c_str());
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index d13b318ace..0147d3cd90 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -86,7 +86,7 @@ protected:
byte *_trackEnd;
public:
- MidiParser_MSC() : byte_11C5A(false) {
+ MidiParser_MSC() : byte_11C5A(false), _beats(0), _lastEvent(0), _trackEnd(NULL) {
}
};
@@ -467,6 +467,11 @@ SoundMan_br::SoundMan_br(Parallaction_br *vm) : _vm(vm) {
_musicEnabled = true;
_sfxEnabled = true;
+
+ _sfxLooping = false;
+ _sfxVolume = 0;
+ _sfxRate = 0;
+ _sfxChannel = 0;
}
SoundMan_br::~SoundMan_br() {
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index 692389b490..6073f82b82 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -323,6 +323,11 @@ void AmigaSoundMan_ns::playLocationMusic(const char *location) {
SoundMan_ns::SoundMan_ns(Parallaction_ns *vm) : _vm(vm) {
_mixer = _vm->_mixer;
+ _sfxLooping = false;
+ _sfxVolume = 0;
+ _sfxRate = 0;
+ _sfxChannel = 0;
+ _musicType = 0;
}
void SoundMan_ns::setMusicVolume(int value) {
@@ -330,7 +335,7 @@ void SoundMan_ns::setMusicVolume(int value) {
}
void SoundMan_ns::setMusicFile(const char *filename) {
- strcpy(_musicFile, filename);
+ Common::strlcpy(_musicFile, filename, PATH_LEN);
}
void SoundMan_ns::execute(int command, const char *parm = 0) {
diff --git a/engines/pegasus/configure.engine b/engines/pegasus/configure.engine
index ed7e295287..650d57a602 100644
--- a/engines/pegasus/configure.engine
+++ b/engines/pegasus/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine pegasus "The Journeyman Project: Pegasus Prime" yes "" "" "16bit"
+add_engine pegasus "The Journeyman Project: Pegasus Prime" yes "" "" "16bit highres"
diff --git a/engines/pegasus/detection.cpp b/engines/pegasus/detection.cpp
index 721c382d4f..161a133c8b 100644
--- a/engines/pegasus/detection.cpp
+++ b/engines/pegasus/detection.cpp
@@ -134,7 +134,7 @@ static const PegasusGameDescription gameDescriptions[] = {
class PegasusMetaEngine : public AdvancedMetaEngine {
public:
PegasusMetaEngine() : AdvancedMetaEngine(Pegasus::gameDescriptions, sizeof(Pegasus::PegasusGameDescription), pegasusGames) {
- _singleid = "pegasus";
+ _singleId = "pegasus";
}
virtual const char *getName() const {
diff --git a/engines/pegasus/input.h b/engines/pegasus/input.h
index ba6f11dba0..ac5b149413 100644
--- a/engines/pegasus/input.h
+++ b/engines/pegasus/input.h
@@ -451,7 +451,7 @@ protected:
class Tracker : public InputHandler {
public:
- Tracker() : InputHandler(0) {}
+ Tracker() : InputHandler(0), _savedHandler(nullptr) {}
virtual ~Tracker() {}
virtual void handleInput(const Input &, const Hotspot *);
diff --git a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
index 688fb7860d..9a2cf8c4bb 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoria4dsystem.cpp
@@ -104,6 +104,14 @@ static const ExtraID s_shutDownExtras[3][3] = {
Caldoria4DSystem::Caldoria4DSystem(Neighborhood *owner) : GameInteraction(kCaldoria4DInteractionID, owner),
_4DSpritesMovie(kCaldoria4DSpritesID) {
+ _4DSpritesScale = 0;
+ _whichMenu = k4DVideoMenu;
+ _videoChoice = k4DIslandChoice;
+ _audioChoice = k4DRockChoice;
+ _neighborhoodNotification = nullptr;
+ _loopStart = 0;
+ _clickedHotspotID = kNoHotSpotID;
+
g_AIArea->lockAIOut();
}
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
index 2ae990d775..54c8b514d1 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamessages.cpp
@@ -35,6 +35,8 @@ static const NotificationFlags kMessageDoneFlag = 1;
CaldoriaMessages::CaldoriaMessages(Neighborhood *owner, const NotificationID id, NotificationManager *manager) :
GameInteraction(kCaldoriaMessagesInteractionID, owner), Notification(id, manager), _messageMovie(kCaldoriaMessagesID) {
+ _neighborhoodNotification = nullptr;
+ _messageNumber = 0;
}
void CaldoriaMessages::openInteraction() {
diff --git a/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
index ff4d1811d0..e0e9e2f22d 100644
--- a/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
+++ b/engines/pegasus/neighborhood/caldoria/caldoriamirror.cpp
@@ -32,6 +32,7 @@
namespace Pegasus {
CaldoriaMirror::CaldoriaMirror(Neighborhood *owner) : GameInteraction(kCaldoriaMirrorInteractionID, owner) {
+ _neighborhoodNotification = nullptr;
}
void CaldoriaMirror::openInteraction() {
diff --git a/engines/pegasus/neighborhood/mars/mars.cpp b/engines/pegasus/neighborhood/mars/mars.cpp
index df5a75541c..0d5edd85ba 100644
--- a/engines/pegasus/neighborhood/mars/mars.cpp
+++ b/engines/pegasus/neighborhood/mars/mars.cpp
@@ -100,6 +100,14 @@ Mars::Mars(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextH
_planetMovie(kNoDisplayElement), _junk(kNoDisplayElement), _energyChoiceSpot(kShuttleEnergySpotID),
_gravitonChoiceSpot(kShuttleGravitonSpotID), _tractorChoiceSpot(kShuttleTractorSpotID),
_shuttleViewSpot(kShuttleViewSpotID), _shuttleTransportSpot(kShuttleTransportSpotID) {
+
+ _reactorStage = 0;
+ _nextGuess = 0;
+ _attackingItem = nullptr;
+ _marsEvent.mars = nullptr;
+ _marsEvent.event = kMarsLaunchTubeReached;
+ _weaponSelection = kNoWeapon;
+
_noAirFuse.setFunctor(new Common::Functor0Mem<void, Mars>(this, &Mars::airStageExpired));
setIsItemTaken(kMarsCard);
setIsItemTaken(kAirMask);
@@ -1950,7 +1958,7 @@ void Mars::pickedUpItem(Item *item) {
}
void Mars::dropItemIntoRoom(Item *item, Hotspot *dropSpot) {
- if (dropSpot->getObjectID() == kAttackRobotHotSpotID) {
+ if (dropSpot && dropSpot->getObjectID() == kAttackRobotHotSpotID) {
_attackingItem = (InventoryItem *)item;
startExtraSequence(kMars48RobotDefends, kExtraCompletedFlag, kFilterNoInput);
loadLoopSound2("");
diff --git a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
index 6a24113465..5c2af3eec2 100644
--- a/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
+++ b/engines/pegasus/neighborhood/norad/alpha/noradalpha.cpp
@@ -93,6 +93,7 @@ NoradAlpha::NoradAlpha(InputHandler *nextHandler, PegasusEngine *owner) : Norad(
_subControlRoom = kNorad22West;
_subPrepFailed = false;
+ _fillingStationItem = nullptr;
setIsItemTaken(kGasCanister);
}
diff --git a/engines/pegasus/neighborhood/norad/delta/globegame.cpp b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
index 9ea3036024..434b95c978 100644
--- a/engines/pegasus/neighborhood/norad/delta/globegame.cpp
+++ b/engines/pegasus/neighborhood/norad/delta/globegame.cpp
@@ -42,6 +42,9 @@ GlobeTracker::GlobeTracker(Movie *globeMovie, Picture *leftHighlight, Picture *r
_rightHighlight = rightHighlight;
_upHighlight = upHighlight;
_downHighlight = downHighlight;
+ _trackSpot = nullptr;
+ _trackTime = -1;
+ _trackDirection = kTrackDown;
}
void GlobeTracker::setTrackParameters(const Hotspot *trackSpot, GlobeTrackDirection direction) {
diff --git a/engines/pegasus/neighborhood/norad/pressuretracker.cpp b/engines/pegasus/neighborhood/norad/pressuretracker.cpp
index 5aac19dcbe..390e3e33b6 100644
--- a/engines/pegasus/neighborhood/norad/pressuretracker.cpp
+++ b/engines/pegasus/neighborhood/norad/pressuretracker.cpp
@@ -34,6 +34,7 @@ PressureTracker::PressureTracker(PressureDoor *pressureDoor) {
_pressureDoor = pressureDoor;
_trackSpot = 0;
_trackTime = 0;
+ _trackButton = nullptr;
}
void PressureTracker::setTrackParameters(const Hotspot *trackSpot, Sprite *trackButton) {
diff --git a/engines/pegasus/neighborhood/wsc/wsc.cpp b/engines/pegasus/neighborhood/wsc/wsc.cpp
index 5e35d8ccc1..c907bee289 100644
--- a/engines/pegasus/neighborhood/wsc/wsc.cpp
+++ b/engines/pegasus/neighborhood/wsc/wsc.cpp
@@ -486,6 +486,12 @@ static const CoordType kMoleculesMovieTop = kNavAreaTop + 40;
WSC::WSC(InputHandler *nextHandler, PegasusEngine *owner) : Neighborhood(nextHandler, owner, "WSC", kWSCID),
_moleculesMovie(kNoDisplayElement) {
+
+ _argonSprite = nullptr;
+ _cachedZoomSpot = nullptr;
+ _moleculeGameLevel = 0;
+ _numCorrect = 0;
+
setIsItemTaken(kArgonCanister);
setIsItemTaken(kSinclairKey);
setIsItemTaken(kNitrogenCanister);
diff --git a/engines/pegasus/pegasus.h b/engines/pegasus/pegasus.h
index d88545a4d1..57ae910def 100644
--- a/engines/pegasus/pegasus.h
+++ b/engines/pegasus/pegasus.h
@@ -23,8 +23,8 @@
*
*/
-#ifndef PEGASUS_H
-#define PEGASUS_H
+#ifndef PEGASUS_PEGASUS_H
+#define PEGASUS_PEGASUS_H
#include "common/list.h"
#include "common/macresman.h"
diff --git a/engines/prince/configure.engine b/engines/prince/configure.engine
index 50740d9f41..827579b00d 100644
--- a/engines/prince/configure.engine
+++ b/engines/prince/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine prince "The Prince and The Coward" no
+add_engine prince "The Prince and The Coward" no "" "" "highres"
diff --git a/engines/prince/debugger.cpp b/engines/prince/debugger.cpp
index fc216e0cfb..661b563944 100644
--- a/engines/prince/debugger.cpp
+++ b/engines/prince/debugger.cpp
@@ -37,6 +37,8 @@ Debugger::Debugger(PrinceEngine *vm, InterpreterFlags *flags) : GUI::Debugger(),
registerCmd("initroom", WRAP_METHOD(Debugger, Cmd_InitRoom));
registerCmd("changecursor", WRAP_METHOD(Debugger, Cmd_ChangeCursor));
registerCmd("additem", WRAP_METHOD(Debugger, Cmd_AddItem));
+
+ _cursorNr = 0;
}
static int strToInt(const char *s) {
diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp
index 3fe7993fdb..1c6f63aff3 100644
--- a/engines/prince/detection.cpp
+++ b/engines/prince/detection.cpp
@@ -29,7 +29,7 @@ int PrinceEngine::getGameType() const {
}
const char *PrinceEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 PrinceEngine::getFeatures() const {
diff --git a/engines/prince/detection.h b/engines/prince/detection.h
index 7e5bdd6b7b..3076253cf5 100644
--- a/engines/prince/detection.h
+++ b/engines/prince/detection.h
@@ -104,7 +104,7 @@ const static char *directoryGlobs[] = {
class PrinceMetaEngine : public AdvancedMetaEngine {
public:
PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) {
- _singleid = "prince";
+ _singleId = "prince";
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
diff --git a/engines/prince/graphics.cpp b/engines/prince/graphics.cpp
index d5178efc17..ea8c52a45b 100644
--- a/engines/prince/graphics.cpp
+++ b/engines/prince/graphics.cpp
@@ -44,6 +44,8 @@ GraphicsMan::GraphicsMan(PrinceEngine *vm) : _vm(vm), _changed(false) {
_shadowTable70 = (byte *)malloc(256);
_shadowTable50 = (byte *)malloc(256);
+
+ _roomBackground = 0;
}
GraphicsMan::~GraphicsMan() {
diff --git a/engines/prince/mob.h b/engines/prince/mob.h
index 0ea610dd8f..863fd3a319 100644
--- a/engines/prince/mob.h
+++ b/engines/prince/mob.h
@@ -35,7 +35,7 @@ namespace Prince {
class Mob {
public:
- Mob() : _name(""), _examText("") {}
+ Mob() : _name(""), _examText(""), _visible(false), _type(0), _mask(0), _examDirection(kDirL), _useDirection(kDirL) {}
bool loadFromStream(Common::SeekableReadStream &stream);
diff --git a/engines/prince/module.mk b/engines/prince/module.mk
index b1be123d4b..27bbc21700 100644
--- a/engines/prince/module.mk
+++ b/engines/prince/module.mk
@@ -19,7 +19,8 @@ MODULE_OBJS = \
saveload.o \
script.o \
sound.o \
- variatxt.o
+ variatxt.o \
+ videoplayer.o
# This module can be built as a plugin
ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN)
diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp
index 55f12a6560..b1a5438978 100644
--- a/engines/prince/prince.cpp
+++ b/engines/prince/prince.cpp
@@ -41,6 +41,7 @@
#include "engines/advancedDetector.h"
#include "audio/audiostream.h"
+#include "audio/decoders/wave.h"
#include "prince/prince.h"
#include "prince/font.h"
@@ -106,8 +107,6 @@ PrinceEngine::PrinceEngine(OSystem *syst, const PrinceGameDescription *gameDesc)
DebugMan.enableDebugChannel("script");
memset(_audioStream, 0, sizeof(_audioStream));
-
- gDebugLevel = 10;
}
PrinceEngine::~PrinceEngine() {
@@ -225,8 +224,8 @@ void PrinceEngine::init() {
error("Can't open all/databank.ptc");
PtcArchive *voices = new PtcArchive();
- if (!voices->open("data/voices/databank.ptc"))
- error("Can't open data/voices/databank.ptc");
+ if (!voices->open("voices/databank.ptc"))
+ error("Can't open voices/databank.ptc");
PtcArchive *sound = new PtcArchive();
if (!sound->open("sound/databank.ptc"))
@@ -240,9 +239,12 @@ void PrinceEngine::init() {
SearchMan.addSubDirectoryMatching(gameDataDir, "all");
- SearchMan.add("all", all);
- SearchMan.add("voices", voices);
- SearchMan.add("sound", sound);
+ // Prefix the archive names, so that "all" doesn't conflict with the
+ // "all" directory, if that happens to be named in all lower case.
+ // It isn't on the CD, but we should try to stay case-insensitive.
+ SearchMan.add("_all", all);
+ SearchMan.add("_voices", voices);
+ SearchMan.add("_sound", sound);
if (getLanguage() != Common::PL_POL && getLanguage() != Common::DE_DEU) {
SearchMan.add("translation", translation);
}
@@ -443,6 +445,7 @@ Common::Error PrinceEngine::run() {
int startGameSlot = ConfMan.hasKey("save_slot") ? ConfMan.getInt("save_slot") : -1;
init();
if (startGameSlot == -1) {
+ playVideo("topware.avi");
showLogo();
} else {
loadLocation(59); // load intro location - easiest way to set everything up
@@ -622,6 +625,8 @@ void PrinceEngine::changeCursor(uint16 curId) {
const Graphics::Surface *curSurface = nullptr;
switch (curId) {
+ default:
+ error("Unknown cursor Id: %d", curId);
case 0:
CursorMan.showMouse(false);
_optionsFlag = 0;
@@ -1542,20 +1547,18 @@ void PrinceEngine::showAnim(Anim &anim) {
// make_special_shadow
if ((anim._flags & 0x80)) {
- if (animSurface) {
- DrawNode newDrawNode;
- newDrawNode.posX = x;
- newDrawNode.posY = y + animSurface->h - anim._shadowBack;
- newDrawNode.posZ = Hero::kHeroShadowZ;
- newDrawNode.width = 0;
- newDrawNode.height = 0;
- newDrawNode.scaleValue = _scaleValue;
- newDrawNode.originalRoomSurface = nullptr;
- newDrawNode.data = this;
- newDrawNode.drawFunction = &Hero::showHeroShadow;
- newDrawNode.s = animSurface;
- _drawNodeList.push_back(newDrawNode);
- }
+ DrawNode newDrawNode;
+ newDrawNode.posX = x;
+ newDrawNode.posY = y + animSurface->h - anim._shadowBack;
+ newDrawNode.posZ = Hero::kHeroShadowZ;
+ newDrawNode.width = 0;
+ newDrawNode.height = 0;
+ newDrawNode.scaleValue = _scaleValue;
+ newDrawNode.originalRoomSurface = nullptr;
+ newDrawNode.data = this;
+ newDrawNode.drawFunction = &Hero::showHeroShadow;
+ newDrawNode.s = animSurface;
+ _drawNodeList.push_back(newDrawNode);
}
//ShowFrameCodeShadow
diff --git a/engines/prince/prince.h b/engines/prince/prince.h
index 6dce044a41..5e07de691f 100644
--- a/engines/prince/prince.h
+++ b/engines/prince/prince.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef PRINCE_H
-#define PRINCE_H
+#ifndef PRINCE_PRINCE_H
+#define PRINCE_PRINCE_H
#include "common/random.h"
#include "common/system.h"
@@ -262,6 +262,8 @@ public:
virtual Common::Error saveGameState(int slot, const Common::String &desc);
virtual Common::Error loadGameState(int slot);
+ void playVideo(Common::String videoFilename);
+
static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
Common::String generateSaveName(int slot);
void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
diff --git a/engines/prince/saveload.cpp b/engines/prince/saveload.cpp
index 46e598be70..d3360badd1 100644
--- a/engines/prince/saveload.cpp
+++ b/engines/prince/saveload.cpp
@@ -63,7 +63,7 @@ SaveStateList PrinceMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp
index 4ed3cee6f3..89e22b586e 100644
--- a/engines/prince/script.cpp
+++ b/engines/prince/script.cpp
@@ -400,9 +400,12 @@ bool Script::loadAllMasks(Common::Array<Mask> &maskList, int offset) {
return false;
}
delete msStream;
+
+ tempMask._width = tempMask.getWidth();
+ tempMask._height = tempMask.getHeight();
+ } else {
+ return false;
}
- tempMask._width = tempMask.getWidth();
- tempMask._height = tempMask.getHeight();
}
maskList.push_back(tempMask);
diff --git a/engines/prince/sound.cpp b/engines/prince/sound.cpp
index 032297ee43..22db9c4998 100644
--- a/engines/prince/sound.cpp
+++ b/engines/prince/sound.cpp
@@ -20,15 +20,13 @@
*
*/
-#include "prince/prince.h"
#include "prince/sound.h"
#include "prince/musNum.h"
-#include "common/config-manager.h"
-#include "common/memstream.h"
#include "common/archive.h"
-#include "audio/decoders/raw.h"
-#include "audio/audiostream.h"
+#include "common/debug.h"
+#include "audio/mididrv.h"
+#include "audio/midiparser.h"
namespace Prince {
@@ -120,6 +118,7 @@ const uint8 MusicPlayer::_musRoomTable[] = {
MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) {
_data = nullptr;
+ _dataSize = 0;
_isGM = false;
MidiPlayer::createDriver();
diff --git a/engines/prince/sound.h b/engines/prince/sound.h
index cc44b0a110..4257a4a37b 100644
--- a/engines/prince/sound.h
+++ b/engines/prince/sound.h
@@ -23,13 +23,7 @@
#ifndef PRINCE_SOUND_H
#define PRINCE_SOUND_H
-#include "audio/audiostream.h"
-#include "audio/decoders/wave.h"
-#include "audio/fmopl.h"
-#include "audio/mididrv.h"
-#include "audio/midiparser.h"
#include "audio/midiplayer.h"
-#include "audio/mixer.h"
#include "common/memstream.h"
namespace Prince {
diff --git a/engines/prince/videoplayer.cpp b/engines/prince/videoplayer.cpp
new file mode 100644
index 0000000000..0d07dea10a
--- /dev/null
+++ b/engines/prince/videoplayer.cpp
@@ -0,0 +1,84 @@
+/* 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.
+ *
+ */
+
+#include "prince/prince.h"
+#include "engines/util.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "video/avi_decoder.h"
+
+namespace Prince {
+
+void PrinceEngine::playVideo(Common::String videoFilename) {
+ // Set the correct video mode
+ initGraphics(640, 480, true, 0);
+ if (_system->getScreenFormat().bytesPerPixel == 1) {
+ warning("Couldn't switch to a RGB color video mode to play a video.");
+ return;
+ }
+
+ debug(2, "Screen format: %s", _system->getScreenFormat().toString().c_str());
+
+ Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
+ if (!videoDecoder->loadFile(videoFilename)) {
+ delete videoDecoder;
+ warning("Unable to open video %s", videoFilename.c_str());
+ initGraphics(640, 480, true);
+ return;
+ }
+
+ videoDecoder->start();
+
+ bool skipVideo = false;
+
+ while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ if (frame->format.bytesPerPixel > 1) {
+ Graphics::Surface *frame1 = frame->convertTo(_system->getScreenFormat());
+ _system->copyRectToScreen(frame1->getPixels(), frame1->pitch, 0, 0, frame1->w, frame1->h);
+ frame1->free();
+ delete frame1;
+ } else {
+ _system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
+ }
+ _system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (_system->getEventManager()->pollEvent(event)) {
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) ||
+ event.type == Common::EVENT_LBUTTONUP)
+ skipVideo = true;
+ }
+
+ _system->delayMillis(10);
+ }
+
+ delete videoDecoder;
+
+ initGraphics(640, 480, true);
+}
+
+} // End of namespace Prince
diff --git a/engines/queen/detection.cpp b/engines/queen/detection.cpp
index 4e87b7e5c2..aed8b7dcb1 100644
--- a/engines/queen/detection.cpp
+++ b/engines/queen/detection.cpp
@@ -105,6 +105,19 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
+ // DOS Demo - English (from Bugreport #6946)
+ {
+ {
+ "queen",
+ "Demo Alt",
+ AD_ENTRY1s("queen.1", "2871fc6f8090f37fa1a0c556a1c97460", 3735447),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO,
+ GUIO1(GUIO_NOSPEECH)
+ },
+ },
+
// DOS Interview Demo - English
{
{
@@ -131,20 +144,18 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
-#if 0
// Amiga Floppy - English
{
{
"queen",
"Floppy",
- AD_ENTRY1s("queen.1", NULL, 351775), // TODO: Fill in correct MD5
+ AD_ENTRY1s("queen.1", "9c209c2cbc1730e3138663c4fd29c2e8", 351775),
Common::EN_ANY,
Common::kPlatformAmiga,
ADGF_NO_FLAGS,
GUIO1(GUIO_NOSPEECH)
},
},
-#endif
// DOS Floppy - English
{
@@ -198,6 +209,19 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
+ // DOS Floppy - Russian (From Bugreport #6946)
+ {
+ {
+ "queen",
+ "Floppy",
+ AD_ENTRY1s("queen.1", "f5e827645d3c887be3bdf4729d847756", 22677657),
+ Common::RU_RUS,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOSPEECH)
+ },
+ },
+
// DOS CD - French
{
{
@@ -211,35 +235,31 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
-#if 0
// DOS Floppy - German
{
{
"queen",
"Floppy",
- AD_ENTRY1s("queen.1", NULL, 22240013), // TODO: Fill in correct MD5
+ AD_ENTRY1s("queen.1", "f5e827645d3c887be3bdf4729d847756", 22240013),
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GUIO_NOSPEECH)
},
},
-#endif
-#if 0
// DOS CD - German
{
{
"queen",
"Talkie",
- AD_ENTRY1s("queen.1", NULL, 217648975), // TODO: Fill in correct MD5
+ AD_ENTRY1s("queen.1", "551d595be8af890fc4cb8533c9c5f5f1", 217648975),
Common::DE_DEU,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GAMEOPTION_ALT_INTRO)
},
},
-#endif
#if 0
// DOS CD - Hebrew
@@ -256,20 +276,18 @@ static const QueenGameDescription gameDescriptions[] = {
},
#endif
-#if 0
// DOS Floppy - Italian
{
{
"queen",
"Floppy",
- AD_ENTRY1s("queen.1", NULL, 22461366), // TODO: Fill in correct MD5
+ AD_ENTRY1s("queen.1", "f5e827645d3c887be3bdf4729d847756", 22461366),
Common::IT_ITA,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GUIO_NOSPEECH)
},
},
-#endif
// DOS CD - Italian
{
@@ -284,20 +302,18 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
-#if 0
// DOS CD - Spanish
{
{
"queen",
"Talkie",
- AD_ENTRY1s("queen.1", NULL, 190730602), // TODO: Fill in correct MD5
+ AD_ENTRY1s("queen.1", "b6302bccf70463de3d5faf0f0628f742", 190730602),
Common::ES_ESP,
Common::kPlatformDOS,
ADGF_NO_FLAGS,
GUIO1(GAMEOPTION_ALT_INTRO)
},
},
-#endif
// DOS CD - English (Compressed Freeware Release v1.0)
{
@@ -377,6 +393,19 @@ static const QueenGameDescription gameDescriptions[] = {
},
},
+ // DOS CD - Hungarian (Compressed Freeware Release v1.02)
+ {
+ {
+ "queen",
+ "Talkie",
+ AD_ENTRY1s("queen.1c", "21fd690b372f8a6289f6f33bc986276c", 51329031),
+ Common::HU_HUN,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GAMEOPTION_ALT_INTRO)
+ },
+ },
+
// TODO: Freeware Release for Spanish DOS CD is missing.
#if 0
// DOS CD - Spanish (Compressed Freeware Release v1.0)
@@ -401,7 +430,7 @@ static const QueenGameDescription gameDescriptions[] = {
class QueenMetaEngine : public AdvancedMetaEngine {
public:
QueenMetaEngine() : AdvancedMetaEngine(Queen::gameDescriptions, sizeof(Queen::QueenGameDescription), queenGames, optionsList) {
- _singleid = "queen";
+ _singleId = "queen";
}
virtual const char *getName() const {
@@ -443,25 +472,25 @@ const ADGameDescription *QueenMetaEngine::fallbackDetect(const FileMap &allFiles
}
Queen::DetectedGameVersion version;
if (Queen::Resource::detectVersion(&version, &dataFile)) {
- desc.gameid = "queen";
+ desc.gameId = "queen";
desc.language = version.language;
desc.platform = version.platform;
desc.flags = ADGF_NO_FLAGS;
- desc.guioptions = GUIO0();
+ desc.guiOptions = GUIO0();
if (version.features & Queen::GF_DEMO) {
desc.extra = "Demo";
desc.flags = ADGF_DEMO;
- desc.guioptions = GUIO_NOSPEECH;
+ desc.guiOptions = GUIO_NOSPEECH;
} else if (version.features & Queen::GF_INTERVIEW) {
desc.extra = "Interview";
desc.flags = ADGF_DEMO;
- desc.guioptions = GUIO_NOSPEECH;
+ desc.guiOptions = GUIO_NOSPEECH;
} else if (version.features & Queen::GF_FLOPPY) {
desc.extra = "Floppy";
- desc.guioptions = GUIO_NOSPEECH;
+ desc.guiOptions = GUIO_NOSPEECH;
} else if (version.features & Queen::GF_TALKIE) {
desc.extra = "Talkie";
- desc.guioptions = GAMEOPTION_ALT_INTRO;
+ desc.guiOptions = GAMEOPTION_ALT_INTRO;
}
return (const ADGameDescription *)&desc;
}
diff --git a/engines/queen/queen.h b/engines/queen/queen.h
index c00e1b3a70..789025c264 100644
--- a/engines/queen/queen.h
+++ b/engines/queen/queen.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef QUEEN_H
-#define QUEEN_H
+#ifndef QUEEN_QUEEN_H
+#define QUEEN_QUEEN_H
#include "engines/engine.h"
#include "common/random.h"
diff --git a/engines/queen/sound.cpp b/engines/queen/sound.cpp
index 63e24454c1..d715d3737e 100644
--- a/engines/queen/sound.cpp
+++ b/engines/queen/sound.cpp
@@ -35,10 +35,10 @@
#include "audio/audiostream.h"
#include "audio/decoders/flac.h"
-#include "audio/mididrv.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/vorbis.h"
+#include "audio/mods/rjp1.h"
#define SB_HEADER_SIZE_V104 110
#define SB_HEADER_SIZE_V110 122
diff --git a/engines/queen/sound.h b/engines/queen/sound.h
index d06d93b9e1..f5d3970b80 100644
--- a/engines/queen/sound.h
+++ b/engines/queen/sound.h
@@ -23,10 +23,11 @@
#ifndef QUEEN_SOUND_H
#define QUEEN_SOUND_H
-#include "common/util.h"
#include "audio/mixer.h"
-#include "audio/mods/rjp1.h"
-#include "queen/defs.h"
+
+namespace Audio {
+class AudioStream;
+}
namespace Common {
class File;
diff --git a/engines/saga/configure.engine b/engines/saga/configure.engine
index 99e2ab367b..adb904a6dd 100644
--- a/engines/saga/configure.engine
+++ b/engines/saga/configure.engine
@@ -1,5 +1,5 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine saga "SAGA" yes "ihnm saga2" "ITE"
-add_engine ihnm "IHNM" yes
-add_engine saga2 "SAGA 2 games" no
+add_engine ihnm "IHNM" yes "" "" "highres"
+add_engine saga2 "SAGA 2 games" no "" "" "highres"
diff --git a/engines/saga/detection.cpp b/engines/saga/detection.cpp
index e201612beb..0677e84d67 100644
--- a/engines/saga/detection.cpp
+++ b/engines/saga/detection.cpp
@@ -102,11 +102,11 @@ static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = {
class SagaMetaEngine : public AdvancedMetaEngine {
public:
SagaMetaEngine() : AdvancedMetaEngine(Saga::gameDescriptions, sizeof(Saga::SAGAGameDescription), sagaGames) {
- _singleid = "saga";
+ _singleId = "saga";
}
- virtual GameDescriptor findGame(const char *gameid) const {
- return Engines::findGameID(gameid, _gameids, obsoleteGameIDsTable);
+ virtual GameDescriptor findGame(const char *gameId) const {
+ return Engines::findGameID(gameId, _gameIds, obsoleteGameIDsTable);
}
virtual const char *getName() const {
diff --git a/engines/saga/detection_tables.h b/engines/saga/detection_tables.h
index 8b3a0e5207..71225ceb2f 100644
--- a/engines/saga/detection_tables.h
+++ b/engines/saga/detection_tables.h
@@ -733,6 +733,36 @@ static const SAGAGameDescription gameDescriptions[] = {
GUIO1(GUIO_NOASPECT)
},
GID_IHNM,
+ GF_IHNM_COLOR_FIX,
+ IHNM_DEFAULT_SCENE,
+ &IHNM_Resources,
+ ARRAYSIZE(IHNMCD_GameFonts),
+ IHNMCD_GameFonts,
+ NULL,
+ },
+
+ // I Have No Mouth And I Must Scream - German fan CD translation
+ // English CD version with German text patch (with Nimdok)
+ // (English speech - German text)
+ {
+ {
+ "ihnm",
+ "fan-made",
+ {
+ {"musicfm.res", GAME_MUSICFILE_FM, "0439083e3dfdc51b486071d45872ae52", 302676},
+ {"musicgm.res", GAME_MUSICFILE_GM, "80f875a1fb384160d1f4b27166eef583", 314020},
+ {"scream.res", GAME_RESOURCEFILE, "46bbdc65d164ba7e89836a0935eec8e6", 79219797},
+ {"scripts.res", GAME_SCRIPTFILE, "be38bbc5a26be809dbf39f13befebd01", 523800},
+ {"patch.re_", GAME_PATCHFILE | GAME_RESOURCEFILE, "58b79e61594779513c7f2d35509fa89e", 5038599},
+ {"sfx.res", GAME_SOUNDFILE, "1c610d543f32ec8b525e3f652536f269", 22561056},
+ { NULL, 0, NULL, 0}
+ },
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GID_IHNM,
0,
IHNM_DEFAULT_SCENE,
&IHNM_Resources,
@@ -761,7 +791,7 @@ static const SAGAGameDescription gameDescriptions[] = {
GUIO1(GUIO_NOASPECT)
},
GID_IHNM,
- 0,
+ GF_IHNM_COLOR_FIX,
IHNM_DEFAULT_SCENE,
&IHNM_Resources,
ARRAYSIZE(IHNMCD_GameFonts),
@@ -790,7 +820,7 @@ static const SAGAGameDescription gameDescriptions[] = {
GUIO1(GUIO_NOASPECT)
},
GID_IHNM,
- 0,
+ GF_IHNM_COLOR_FIX,
IHNM_DEFAULT_SCENE,
&IHNM_Resources,
ARRAYSIZE(IHNMCD_GameFonts),
diff --git a/engines/saga/displayinfo.h b/engines/saga/displayinfo.h
index a0cdf5733b..67448936ce 100644
--- a/engines/saga/displayinfo.h
+++ b/engines/saga/displayinfo.h
@@ -177,11 +177,11 @@ static PanelButton ITE_OptionPanelButtons[] = {
{kPanelButtonOption, 241,98, 57,17, kTextSave,'s',0, 0,0,0}, //save
{kPanelButtonOptionSaveFiles, 166,20, 112,74, 0,'-',0, 0,0,0}, //savefiles
- {kPanelButtonOptionText,106,4, 0,0, kTextGameOptions,'-',0, 0,0,0}, // text: game options
- {kPanelButtonOptionText,11,22, 0,0, kTextReadingSpeed,'-',0, 0,0,0}, // text: read speed
- {kPanelButtonOptionText,28,22, 0,0, kTextShowDialog,'-',0, 0,0,0}, // text: read speed
- {kPanelButtonOptionText,73,41, 0,0, kTextMusic,'-',0, 0,0,0}, // text: music
- {kPanelButtonOptionText,69,60, 0,0, kTextSound,'-',0, 0,0,0}, // text: noise
+ {kPanelButtonOptionText,-1,4, 0,0, kTextGameOptions,'-',0, 0,0,0}, // text: game options
+ {kPanelButtonOptionText,5,18, 109,17, kTextReadingSpeed,'-',0, 0,0,0}, // text: read speed
+ {kPanelButtonOptionText,5,18, 109,17, kTextShowDialog,'-',0, 0,0,0}, // text: read speed
+ {kPanelButtonOptionText,5,37, 109,17, kTextMusic,'-',0, 0,0,0}, // text: music
+ {kPanelButtonOptionText,5,56, 109,17, kTextSound,'-',0, 0,0,0}, // text: noise
};
static PanelButton ITE_QuitPanelButtons[] = {
@@ -326,10 +326,10 @@ static PanelButton IHNM_ConversePanelButtons[] = {
static PanelButton IHNM_OptionPanelButtons[] = {
{kPanelButtonOptionSlider, 421,16, 16,138, 0,'-',0, 0,0,0}, //slider-scroller
- {kPanelButtonOptionText,28,36, 0,0, kTextReadingSpeed,'-',0, 0,0,0}, // text: read speed
- {kPanelButtonOptionText,60,61, 0,0, kTextMusic,'-',0, 0,0,0}, // text: music
- {kPanelButtonOptionText,60,86, 0,0, kTextSound,'-',0, 0,0,0}, // text: noise
- {kPanelButtonOptionText,56,111, 0,0, kTextVoices,'-',0, 0,0,0}, // text: voices
+ {kPanelButtonOptionText,11,30, 139,21, kTextReadingSpeed,'-',0, 0,0,0}, // text: read speed
+ {kPanelButtonOptionText,11,55, 139,21, kTextMusic,'-',0, 0,0,0}, // text: music
+ {kPanelButtonOptionText,11,80, 139,21, kTextSound,'-',0, 0,0,0}, // text: noise
+ {kPanelButtonOptionText,11,105, 139,21, kTextVoices,'-',0, 0,0,0}, // text: voices
{kPanelButtonOption, 154,30, 79,23, kTextReadingSpeed,'r',0, 0,0,0}, //read speed
{kPanelButtonOption, 154,55, 79,23, kTextMusic,'m',0, 0,0,0}, //music
{kPanelButtonOption, 154,80, 79,23, kTextSound,'n',0, 0,0,0}, //sound-noise
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index cb42ac0aaa..c663313f01 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -867,7 +867,7 @@ void Interface::calcOptionSaveSlider() {
void Interface::drawPanelText(InterfacePanel *panel, PanelButton *panelButton) {
const char *text;
- int textWidth;
+ int textWidth, textHeight;
Rect rect;
Point textPoint;
KnownColor textShadowKnownColor = kKnownColorVerbTextShadow;
@@ -900,12 +900,26 @@ void Interface::drawPanelText(InterfacePanel *panel, PanelButton *panelButton) {
}
panel->calcPanelButtonRect(panelButton, rect);
+ if (_vm->getGameId() == GID_ITE) {
+ textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
+ textHeight = _vm->_font->getHeight(kKnownFontMedium);
+ } else {
+ textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
+ textHeight = _vm->_font->getHeight(kKnownFontVerb);
+ }
if (panelButton->xOffset < 0) {
- if (_vm->getGameId() == GID_ITE)
- textWidth = _vm->_font->getStringWidth(kKnownFontMedium, text, 0, kFontNormal);
- else
- textWidth = _vm->_font->getStringWidth(kKnownFontVerb, text, 0, kFontNormal);
+ // Special case: Centered to dialog. This is used for things like the
+ // title of a dialog.
rect.left += 2 + (panel->imageWidth - 1 - textWidth) / 2;
+ } else {
+ // The standard case is used for the things that look a bit like buttons
+ // but are not clickable, e.g. texts like "Music", "Sound", etc.
+ if (_vm->getGameId() == GID_ITE) {
+ rect.left = rect.right - textWidth - 3;
+ } else {
+ rect.left = (rect.right + rect.left - textWidth) / 2;
+ }
+ rect.top = (rect.top + rect.bottom - textHeight) / 2;
}
textPoint.x = rect.left;
@@ -1156,7 +1170,7 @@ void Interface::processStatusTextInput(Common::KeyState keystate) {
_statusTextInputPos--;
_statusTextInputString[_statusTextInputPos] = 0;
default:
- if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX) {
+ if (_statusTextInputPos >= STATUS_TEXT_INPUT_MAX - 1) { // -1 because of the null termination
break;
}
if (Common::isAlnum(keystate.ascii) || (keystate.ascii == ' ')) {
@@ -1862,8 +1876,10 @@ void Interface::drawStatusBar() {
int stringWidth;
int color;
// The default colors in the Spanish version of IHNM are shifted by one
- // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)"
- int offset = (_vm->getLanguage() == Common::ES_ESP) ? 1 : 0;
+ // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)". This
+ // also applies to the German and French versions (bug #7064 - "IHNM:
+ // text mistake in german version").
+ int offset = (_vm->getFeatures() & GF_IHNM_COLOR_FIX) ? 1 : 0;
// Disable the status text in IHNM when the chapter is 8
if (_vm->getGameId() == GID_IHNM && _vm->_scene->currentChapterNumber() == 8)
@@ -2283,6 +2299,9 @@ void Interface::drawPanelButtonText(InterfacePanel *panel, PanelButton *panelBut
break;
}
if (_vm->getGameId() == GID_ITE) {
+ if (textId > kTextEnterProtectAnswer)
+ error("This should not happen. Please report to ScummVM Team how you achieved this error.");
+
text = _vm->getTextString(textId);
textFont = kKnownFontMedium;
textShadowKnownColor = kKnownColorVerbTextShadow;
diff --git a/engines/saga/isomap.cpp b/engines/saga/isomap.cpp
index 77680178c1..e50378b9c0 100644
--- a/engines/saga/isomap.cpp
+++ b/engines/saga/isomap.cpp
@@ -97,6 +97,23 @@ IsoMap::IsoMap(SagaEngine *vm) : _vm(vm) {
_viewScroll.x = (128 - 8) * 16;
_viewScroll.y = (128 - 8) * 16 - 64;
_viewDiff = 1;
+ _platformHeight = 0;
+ _queueCount = _readCount = 0;
+
+ for (int i = 0; i < SAGA_DRAGON_SEARCH_DIAMETER; i++)
+ for (int j = 0; j < SAGA_DRAGON_SEARCH_DIAMETER; j++)
+ _dragonSearchArray.cell[i][j].visited = _dragonSearchArray.cell[i][j].direction = 0;
+
+ for (int i = 0; i < SAGA_SEARCH_DIAMETER; i++)
+ for (int j = 0; j < SAGA_SEARCH_DIAMETER; j++)
+ _searchArray.cell[i][j].visited = _searchArray.cell[i][j].direction = 0;
+
+ for (int i = 0; i < SAGA_SEARCH_QUEUE_SIZE; i++) {
+ memset(&_dragonSearchArray.queue[i], 0, sizeof(DragonTilePoint));
+ memset(&_searchArray.queue[i], 0, sizeof(TilePoint));
+ }
+
+ memset(&_tileMap, 0, sizeof(TileMapData));
}
void IsoMap::loadImages(const ByteArray &resourceData) {
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index cd48ebaa4d..0bc1e8a2a0 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -32,7 +32,10 @@
#include "audio/midiparser.h"
#include "audio/midiparser_qt.h"
#include "audio/miles.h"
+#include "audio/decoders/flac.h"
+#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
+#include "audio/decoders/vorbis.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/substream.h"
diff --git a/engines/saga/music.h b/engines/saga/music.h
index 2e7cc4c5ec..0213f4108a 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -25,13 +25,10 @@
#ifndef SAGA_MUSIC_H
#define SAGA_MUSIC_H
+#include "audio/mididrv.h"
#include "audio/midiplayer.h"
#include "audio/midiparser.h"
#include "audio/mixer.h"
-#include "audio/decoders/mp3.h"
-#include "audio/decoders/vorbis.h"
-#include "audio/decoders/flac.h"
-#include "common/mutex.h"
namespace Saga {
diff --git a/engines/saga/puzzle.cpp b/engines/saga/puzzle.cpp
index 099bf79e6b..2c9a02beec 100644
--- a/engines/saga/puzzle.cpp
+++ b/engines/saga/puzzle.cpp
@@ -86,6 +86,11 @@ Puzzle::Puzzle(SagaEngine *vm) : _vm(vm), _solved(false), _active(false) {
_hintBox.setWidth(240);
_hintBox.setHeight(30);
+ _hintNextRqState = kRQNoHint;
+ _hintGiver = 0;
+ _hintSpeaker = 0;
+ _slidePointX = _slidePointY = 0;
+
initPieceInfo( 0, 268, 18, 0, 0, 0 + PUZZLE_X_OFFSET, 0 + PUZZLE_Y_OFFSET, 0, 3,
Point(0, 1), Point(0, 62), Point(15, 31), Point(0, 0), Point(0, 0), Point(0,0));
initPieceInfo( 1, 270, 52, 0, 0, 0 + PUZZLE_X_OFFSET, 32 + PUZZLE_Y_OFFSET, 0, 4,
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 532b59d3c7..649888e7ea 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -578,9 +578,11 @@ ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) {
}
#ifdef ENABLE_IHNM
} else if (getGameId() == GID_IHNM) {
- // The default colors in the Spanish version of IHNM are shifted by one
- // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)"
- int offset = (getLanguage() == Common::ES_ESP) ? 1 : 0;
+ // The default colors in the Spanish, version of IHNM are shifted by one
+ // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)". This
+ // also applies to the German and French versions (bug #7064 - "IHNM:
+ // text mistake in german version").
+ int offset = (getFeatures() & GF_IHNM_COLOR_FIX) ? 1 : 0;
switch (knownColor) {
case(kKnownColorTransparent):
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index 9c7b2f5295..422eaa530d 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SAGA_H
-#define SAGA_H
+#ifndef SAGA_SAGA_H
+#define SAGA_SAGA_H
#include "engines/engine.h"
@@ -139,7 +139,8 @@ enum GameFeatures {
GF_ITE_FLOPPY = 1 << 0,
GF_ITE_DOS_DEMO = 1 << 1,
GF_EXTRA_ITE_CREDITS = 1 << 2,
- GF_8BIT_UNSIGNED_PCM = 1 << 3
+ GF_8BIT_UNSIGNED_PCM = 1 << 3,
+ GF_IHNM_COLOR_FIX = 1 << 4
};
enum VerbTypeIds {
diff --git a/engines/saga/saveload.cpp b/engines/saga/saveload.cpp
index e659e09ce8..1a131bf5cc 100644
--- a/engines/saga/saveload.cpp
+++ b/engines/saga/saveload.cpp
@@ -56,7 +56,7 @@ SaveFileData *SagaEngine::getSaveFile(uint idx) {
return &_saveFiles[_saveFilesCount - idx - 1];
} else {
if (!emptySlot.name[0])
- strcpy(emptySlot.name, getTextString(kTextNewSave));
+ Common::strlcpy(emptySlot.name, getTextString(kTextNewSave), SAVE_TITLE_SIZE);
return (idx == 0) ? &emptySlot : &_saveFiles[_saveFilesCount - idx];
}
@@ -185,7 +185,7 @@ void SagaEngine::save(const char *fileName, const char *saveName) {
// Original game title
memset(title, 0, TITLESIZE);
- strncpy(title, _gameTitle.c_str(), TITLESIZE);
+ Common::strlcpy(title, _gameTitle.c_str(), TITLESIZE);
out->write(title, TITLESIZE);
// Thumbnail
diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp
index efd4c371b1..5cb4b55899 100644
--- a/engines/saga/scene.cpp
+++ b/engines/saga/scene.cpp
@@ -969,9 +969,8 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
case SAGA_OBJECT:
break;
case SAGA_BG_IMAGE: // Scene background resource
- if (_bg.loaded) {
+ if (_bg.loaded)
error("Scene::processSceneResources() Multiple background resources encountered");
- }
debug(3, "Loading background resource.");
@@ -987,9 +986,9 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
memcpy(_bg.pal, palPointer, sizeof(_bg.pal));
break;
case SAGA_BG_MASK: // Scene background mask resource
- if (_bgMask.loaded) {
+ if (_bgMask.loaded)
error("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
- }
+
debug(3, "Loading BACKGROUND MASK resource.");
_vm->decodeBGImage(resourceData, _bgMask.buffer, &_bgMask.w, &_bgMask.h, true);
_bgMask.loaded = true;
@@ -1014,47 +1013,38 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
_actionMap->load(resourceData);
break;
case SAGA_ISO_IMAGES:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric images resource.");
_vm->_isoMap->loadImages(resourceData);
break;
case SAGA_ISO_MAP:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric map resource.");
-
_vm->_isoMap->loadMap(resourceData);
break;
case SAGA_ISO_PLATFORMS:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric platforms resource.");
-
_vm->_isoMap->loadPlatforms(resourceData);
break;
case SAGA_ISO_METATILES:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric metatiles resource.");
-
_vm->_isoMap->loadMetaTiles(resourceData);
break;
case SAGA_ANIM:
{
uint16 animId = resource->resourceType - 14;
-
debug(3, "Loading animation resource animId=%i", animId);
-
_vm->_anim->load(animId, resourceData);
}
break;
@@ -1063,9 +1053,8 @@ void Scene::processSceneResources(SceneResourceDataArray &resourceList) {
loadSceneEntryList(resourceData);
break;
case SAGA_ISO_MULTI:
- if (!(_sceneDescription.flags & kSceneFlagISO)) {
+ if (!(_sceneDescription.flags & kSceneFlagISO))
error("Scene::ProcessSceneResources(): not Iso mode");
- }
debug(3, "Loading isometric multi resource.");
diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp
index 1e1c397212..db67d510bc 100644
--- a/engines/saga/shorten.cpp
+++ b/engines/saga/shorten.cpp
@@ -21,7 +21,9 @@
*/
#include "common/scummsys.h"
+#include "common/stream.h"
#include "common/textconsole.h"
+#include "audio/audiostream.h"
#include "saga/shorten.h"
diff --git a/engines/saga/shorten.h b/engines/saga/shorten.h
index 556abaf311..4d4ec328c6 100644
--- a/engines/saga/shorten.h
+++ b/engines/saga/shorten.h
@@ -30,9 +30,14 @@
#define SOUND_SHORTEN_H
#include "common/scummsys.h"
-#include "common/stream.h"
-#include "audio/audiostream.h"
+namespace Audio {
+class AudioStream;
+}
+
+namespace Common {
+class ReadStream;
+}
namespace Saga {
diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp
index 0eb6f8a82a..f4e31542fe 100644
--- a/engines/saga/sound.cpp
+++ b/engines/saga/sound.cpp
@@ -27,8 +27,6 @@
#include "audio/audiostream.h"
#include "audio/mixer.h"
-#include "audio/decoders/adpcm.h"
-#include "audio/decoders/raw.h"
namespace Saga {
diff --git a/engines/sci/configure.engine b/engines/sci/configure.engine
index d1c45a4654..f8a519002e 100644
--- a/engines/sci/configure.engine
+++ b/engines/sci/configure.engine
@@ -1,4 +1,4 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine sci "SCI" yes "sci32" "SCI 0-1.1 games"
-add_engine sci32 "SCI32 games" no
+add_engine sci32 "SCI32 games" no "" "" "highres"
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index cbc6dfaf74..6898745858 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -41,9 +41,7 @@
#include "sci/graphics/cache.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/screen.h"
-#include "sci/graphics/paint.h"
#include "sci/graphics/paint16.h"
-#include "sci/graphics/paint32.h"
#include "sci/graphics/palette.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/view.h"
@@ -54,6 +52,7 @@
#include "sci/video/seq_decoder.h"
#ifdef ENABLE_SCI32
#include "sci/graphics/frameout.h"
+#include "sci/graphics/paint32.h"
#include "video/coktel_decoder.h"
#include "sci/video/robot_decoder.h"
#endif
@@ -141,6 +140,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
registerCmd("vpl", WRAP_METHOD(Console, cmdVisiblePlaneList)); // alias
registerCmd("plane_items", WRAP_METHOD(Console, cmdPlaneItemList));
registerCmd("pi", WRAP_METHOD(Console, cmdPlaneItemList)); // alias
+ registerCmd("visible_plane_items", WRAP_METHOD(Console, cmdVisiblePlaneItemList));
+ registerCmd("vpi", WRAP_METHOD(Console, cmdVisiblePlaneItemList)); // alias
registerCmd("saved_bits", WRAP_METHOD(Console, cmdSavedBits));
registerCmd("show_saved_bits", WRAP_METHOD(Console, cmdShowSavedBits));
// Segments
@@ -192,6 +193,7 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
registerCmd("send", WRAP_METHOD(Console, cmdSend));
registerCmd("go", WRAP_METHOD(Console, cmdGo));
registerCmd("logkernel", WRAP_METHOD(Console, cmdLogKernel));
+ registerCmd("vocab994", WRAP_METHOD(Console, cmdMapVocab994));
// Breakpoints
registerCmd("bp_list", WRAP_METHOD(Console, cmdBreakpointList));
registerCmd("bplist", WRAP_METHOD(Console, cmdBreakpointList)); // alias
@@ -385,6 +387,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
debugPrintf(" plane_list / pl - Shows a list of all the planes in the draw list (SCI2+)\n");
debugPrintf(" visible_plane_list / vpl - Shows a list of all the planes in the visible draw list (SCI2+)\n");
debugPrintf(" plane_items / pi - Shows a list of all items for a plane (SCI2+)\n");
+ debugPrintf(" visible_plane_items / vpi - Shows a list of all items for a plane in the visible draw list (SCI2+)\n");
debugPrintf(" saved_bits - List saved bits on the hunk\n");
debugPrintf(" show_saved_bits - Display saved bits\n");
debugPrintf("\n");
@@ -494,8 +497,10 @@ bool Console::cmdGetVersion(int argc, const char **argv) {
if (getSciVersion() <= SCI_VERSION_1_1) {
debugPrintf("kAnimate fastCast enabled: %s\n", g_sci->_gfxAnimate->isFastCastEnabled() ? "yes" : "no");
}
- debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no");
- debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no");
+ if (getSciVersion() < SCI_VERSION_2) {
+ debugPrintf("Uses palette merging: %s\n", g_sci->_gfxPalette16->isMerging() ? "yes" : "no");
+ debugPrintf("Uses 16 bit color matching: %s\n", g_sci->_gfxPalette16->isUsing16bitColorMatch() ? "yes" : "no");
+ }
debugPrintf("Resource volume version: %s\n", g_sci->getResMan()->getVolVersionDesc());
debugPrintf("Resource map version: %s\n", g_sci->getResMan()->getMapVersionDesc());
debugPrintf("Contains selector vocabulary (vocab.997): %s\n", hasVocab997 ? "yes" : "no");
@@ -1001,7 +1006,7 @@ bool Console::cmdHexgrep(int argc, const char **argv) {
for (; resNumber <= resMax; resNumber++) {
script = _engine->getResMan()->findResource(ResourceId(restype, resNumber), 0);
if (script) {
- unsigned int seeker = 0, seekerold = 0;
+ uint32 seeker = 0, seekerold = 0;
uint32 comppos = 0;
int output_script_name = 0;
@@ -1507,7 +1512,7 @@ bool Console::cmdSaid(int argc, const char **argv) {
}
// TODO: Maybe turn this into a proper said spec compiler
- unsigned int len = 0;
+ uint32 len = 0;
for (p++; p < argc; p++) {
if (strcmp(argv[p], ",") == 0) {
spec[len++] = 0xf0;
@@ -1544,7 +1549,7 @@ bool Console::cmdSaid(int argc, const char **argv) {
spec[len++] = 0xfe;
spec[len++] = 0xf6;
} else {
- unsigned int s = strtol(argv[p], 0, 16);
+ uint32 s = strtol(argv[p], 0, 16);
if (s >= 0xf0 && s <= 0xff) {
spec[len++] = s;
} else {
@@ -1617,7 +1622,7 @@ bool Console::cmdParserNodes(int argc, const char **argv) {
bool Console::cmdSetPalette(int argc, const char **argv) {
if (argc < 2) {
- debugPrintf("Sets a palette resource\n");
+ debugPrintf("Sets a palette resource (SCI16)\n");
debugPrintf("Usage: %s <resourceId>\n", argv[0]);
debugPrintf("where <resourceId> is the number of the palette resource to set\n");
return true;
@@ -1625,6 +1630,13 @@ bool Console::cmdSetPalette(int argc, const char **argv) {
uint16 resourceId = atoi(argv[1]);
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ debugPrintf("This SCI version does not support this command\n");
+ return true;
+ }
+#endif
+
_engine->_gfxPalette16->kernelSetFromResource(resourceId, true);
return true;
}
@@ -1644,7 +1656,7 @@ bool Console::cmdDrawPic(int argc, const char **argv) {
#endif
uint16 resourceId = atoi(argv[1]);
- _engine->_gfxPaint->kernelDrawPicture(resourceId, 100, false, false, false, 0);
+ _engine->_gfxPaint16->kernelDrawPicture(resourceId, 100, false, false, false, 0);
_engine->_gfxScreen->copyToScreen();
_engine->sleep(2000);
@@ -1816,6 +1828,34 @@ bool Console::cmdPlaneItemList(int argc, const char **argv) {
return true;
}
+bool Console::cmdVisiblePlaneItemList(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Shows the list of items for a plane\n");
+ debugPrintf("Usage: %s <plane address>\n", argv[0]);
+ return true;
+ }
+
+ reg_t planeObject = NULL_REG;
+
+ if (parse_reg_t(_engine->_gamestate, argv[1], &planeObject, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+#ifdef ENABLE_SCI32
+ if (_engine->_gfxFrameout) {
+ debugPrintf("Visible plane item list:\n");
+ _engine->_gfxFrameout->printVisiblePlaneItemList(this, planeObject);
+ } else {
+ debugPrintf("This SCI version does not have a list of plane items\n");
+ }
+#else
+ debugPrintf("SCI32 isn't included in this compiled executable\n");
+#endif
+ return true;
+}
+
bool Console::cmdSavedBits(int argc, const char **argv) {
SegManager *segman = _engine->_gamestate->_segMan;
SegmentId id = segman->findSegmentByType(SEG_TYPE_HUNK);
@@ -1829,7 +1869,7 @@ bool Console::cmdSavedBits(int argc, const char **argv) {
for (uint i = 0; i < entries.size(); ++i) {
uint16 offset = entries[i].getOffset();
- const Hunk& h = hunks->_table[offset];
+ const Hunk& h = hunks->at(offset);
if (strcmp(h.type, "SaveBits()") == 0) {
byte* memoryPtr = (byte *)h.mem;
@@ -1896,7 +1936,7 @@ bool Console::cmdShowSavedBits(int argc, const char **argv) {
return true;
}
- const Hunk& h = hunks->_table[memoryHandle.getOffset()];
+ const Hunk& h = hunks->at(memoryHandle.getOffset());
if (strcmp(h.type, "SaveBits()") != 0) {
debugPrintf("Invalid address.\n");
@@ -2112,32 +2152,32 @@ bool Console::segmentInfo(int nr) {
break;
case SEG_TYPE_CLONES: {
- CloneTable *ct = (CloneTable *)mobj;
+ CloneTable &ct = *(CloneTable *)mobj;
debugPrintf("clones\n");
- for (uint i = 0; i < ct->_table.size(); i++)
- if (ct->isValidEntry(i)) {
+ for (uint i = 0; i < ct.size(); i++)
+ if (ct.isValidEntry(i)) {
reg_t objpos = make_reg(nr, i);
debugPrintf(" [%04x] %s; copy of ", i, _engine->_gamestate->_segMan->getObjectName(objpos));
// Object header
- const Object *obj = _engine->_gamestate->_segMan->getObject(ct->_table[i].getPos());
+ const Object *obj = _engine->_gamestate->_segMan->getObject(ct[i].getPos());
if (obj)
- debugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(ct->_table[i].getPos()),
- _engine->_gamestate->_segMan->getObjectName(ct->_table[i].getPos()),
+ debugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(ct[i].getPos()),
+ _engine->_gamestate->_segMan->getObjectName(ct[i].getPos()),
obj->getVarCount(), obj->getMethodCount());
}
}
break;
case SEG_TYPE_LISTS: {
- ListTable *lt = (ListTable *)mobj;
+ ListTable &lt = *(ListTable *)mobj;
debugPrintf("lists\n");
- for (uint i = 0; i < lt->_table.size(); i++)
- if (lt->isValidEntry(i)) {
+ for (uint i = 0; i < lt.size(); i++)
+ if (lt.isValidEntry(i)) {
debugPrintf(" [%04x]: ", i);
- printList(&(lt->_table[i]));
+ printList(&lt[i]);
}
}
break;
@@ -2148,13 +2188,13 @@ bool Console::segmentInfo(int nr) {
}
case SEG_TYPE_HUNK: {
- HunkTable *ht = (HunkTable *)mobj;
+ HunkTable &ht = *(HunkTable *)mobj;
- debugPrintf("hunk (total %d)\n", ht->entries_used);
- for (uint i = 0; i < ht->_table.size(); i++)
- if (ht->isValidEntry(i)) {
+ debugPrintf("hunk (total %d)\n", ht.entries_used);
+ for (uint i = 0; i < ht.size(); i++)
+ if (ht.isValidEntry(i)) {
debugPrintf(" [%04x] %d bytes at %p, type=%s\n",
- i, ht->_table[i].size, ht->_table[i].mem, ht->_table[i].type);
+ i, ht[i].size, ht[i].mem, ht[i].type);
}
}
break;
@@ -2533,9 +2573,14 @@ bool Console::cmdVMVars(int argc, const char **argv) {
case 1:
case 2:
case 3: {
- // for global, local, temp and param, we need an index
if (argc < 3) {
- debugPrintf("Variable number must be specified for requested type\n");
+ for (int i = 0; i < s->variablesMax[varType]; ++i) {
+ curValue = &s->variables[varType][i];
+ debugPrintf("%s var %d == %04x:%04x", varNames[varType], i, PRINT_REG(*curValue));
+ printBasicVarInfo(*curValue);
+ debugPrintf("\n");
+ }
+
return true;
}
if (argc > 4) {
@@ -3058,7 +3103,10 @@ bool Console::cmdBacktrace(int argc, const char **argv) {
break;
case EXEC_STACK_TYPE_KERNEL: // Kernel function
- debugPrintf(" %x:[%x] k%s(", i, call.debugOrigin, _engine->getKernel()->getKernelName(call.debugSelector).c_str());
+ if (call.debugKernelSubFunction == -1)
+ debugPrintf(" %x:[%x] k%s(", i, call.debugOrigin, _engine->getKernel()->getKernelName(call.debugKernelFunction).c_str());
+ else
+ debugPrintf(" %x:[%x] k%s(", i, call.debugOrigin, _engine->getKernel()->getKernelName(call.debugKernelFunction, call.debugKernelSubFunction).c_str());
break;
case EXEC_STACK_TYPE_VARSELECTOR:
@@ -3923,6 +3971,55 @@ bool Console::cmdSfx01Track(int argc, const char **argv) {
return true;
}
+bool Console::cmdMapVocab994(int argc, const char **argv) {
+ EngineState *s = _engine->_gamestate; // for the several defines in this function
+ reg_t reg;
+
+ if (argc != 4) {
+ debugPrintf("Attempts to map a range of vocab.994 entries to a given class\n");
+ debugPrintf("Usage: %s <class addr> <first> <last>\n", argv[0]);
+ return true;
+ }
+
+ if (parse_reg_t(_engine->_gamestate, argv[1], &reg, false)) {
+ debugPrintf("Invalid address passed.\n");
+ debugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ Resource *resource = _engine->_resMan->findResource(ResourceId(kResourceTypeVocab, 994), 0);
+ const Object *obj = s->_segMan->getObject(reg);
+ uint16 *data = (uint16 *) resource->data;
+ uint32 first = atoi(argv[2]);
+ uint32 last = atoi(argv[3]);
+ Common::Array<bool> markers;
+
+ markers.resize(_engine->getKernel()->getSelectorNamesSize());
+ if (!obj->isClass() && getSciVersion() != SCI_VERSION_3)
+ obj = s->_segMan->getObject(obj->getSuperClassSelector());
+
+ first = MIN(first, (uint32) (resource->size / 2 - 2));
+ last = MIN(last, (uint32) (resource->size / 2 - 2));
+
+ for (uint32 i = first; i <= last; ++i) {
+ uint16 ofs = data[i];
+
+ if (obj && ofs < obj->getVarCount()) {
+ uint16 varSelector = obj->getVarSelector(ofs);
+ debugPrintf("%d: property at index %04x of %s is %s %s\n", i, ofs,
+ s->_segMan->derefString(obj->getNameSelector()),
+ _engine->getKernel()->getSelectorName(varSelector).c_str(),
+ markers[varSelector] ? "(repeat!)" : "");
+ markers[varSelector] = true;
+ }
+ else {
+ debugPrintf("%d: property at index %04x doesn't match up with %s\n", i, ofs,
+ s->_segMan->derefString(obj->getNameSelector()));
+ }
+ }
+
+ return true;
+}
bool Console::cmdQuit(int argc, const char **argv) {
if (argc != 2) {
}
@@ -4281,7 +4378,7 @@ void Console::printList(List *list) {
return;
}
- node = &(nt->_table[pos.getOffset()]);
+ node = &nt->at(pos.getOffset());
debugPrintf("\t%04x:%04x : %04x:%04x -> %04x:%04x\n", PRINT_REG(pos), PRINT_REG(node->key), PRINT_REG(node->value));
@@ -4311,7 +4408,7 @@ int Console::printNode(reg_t addr) {
return 1;
}
- list = &(lt->_table[addr.getOffset()]);
+ list = &lt->at(addr.getOffset());
debugPrintf("%04x:%04x : first x last = (%04x:%04x, %04x:%04x)\n", PRINT_REG(addr), PRINT_REG(list->first), PRINT_REG(list->last));
} else {
@@ -4330,7 +4427,7 @@ int Console::printNode(reg_t addr) {
debugPrintf("Address does not contain a node\n");
return 1;
}
- node = &(nt->_table[addr.getOffset()]);
+ node = &nt->at(addr.getOffset());
debugPrintf("%04x:%04x : prev x next = (%04x:%04x, %04x:%04x); maps %04x:%04x -> %04x:%04x\n",
PRINT_REG(addr), PRINT_REG(node->pred), PRINT_REG(node->succ), PRINT_REG(node->key), PRINT_REG(node->value));
@@ -4361,7 +4458,8 @@ int Console::printObject(reg_t pos) {
debugPrintf(" ");
if (var_container && i < var_container->getVarCount()) {
uint16 varSelector = var_container->getVarSelector(i);
- debugPrintf("[%03x] %s = ", varSelector, _engine->getKernel()->getSelectorName(varSelector).c_str());
+ // Times two commented out for now for easy parsing of vocab.994
+ debugPrintf("(%04x) [%03x] %s = ", i /* *2 */, varSelector, _engine->getKernel()->getSelectorName(varSelector).c_str());
} else
debugPrintf("p#%x = ", i);
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 7c4de02182..cf85def950 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -98,6 +98,7 @@ private:
bool cmdPlaneList(int argc, const char **argv);
bool cmdVisiblePlaneList(int argc, const char **argv);
bool cmdPlaneItemList(int argc, const char **argv);
+ bool cmdVisiblePlaneItemList(int argc, const char **argv);
bool cmdSavedBits(int argc, const char **argv);
bool cmdShowSavedBits(int argc, const char **argv);
// Segments
@@ -138,6 +139,7 @@ private:
bool cmdSend(int argc, const char **argv);
bool cmdGo(int argc, const char **argv);
bool cmdLogKernel(int argc, const char **argv);
+ bool cmdMapVocab994(int argc, const char **argv);
// Breakpoints
bool cmdBreakpointList(int argc, const char **argv);
bool cmdBreakpointDelete(int argc, const char **argv);
diff --git a/engines/sci/decompressor.cpp b/engines/sci/decompressor.cpp
index e65ff148de..ca2298e67e 100644
--- a/engines/sci/decompressor.cpp
+++ b/engines/sci/decompressor.cpp
@@ -257,7 +257,7 @@ int DecompressorLZW::unpackLZW1(Common::ReadStream *src, byte *dest, uint32 nPac
init(src, dest, nPacked, nUnpacked);
byte *stak = (byte *)malloc(0x1014);
- unsigned int tokensSize = 0x1004 * sizeof(Tokenlist);
+ uint32 tokensSize = 0x1004 * sizeof(Tokenlist);
Tokenlist *tokens = (Tokenlist *)malloc(tokensSize);
if (!stak || !tokens) {
free(stak);
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 985e12a7f6..8691c37b3e 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -89,6 +89,7 @@ static const PlainGameDescriptor s_sciGameTitles[] = {
{"ecoquest2", "EcoQuest II: Lost Secret of the Rainforest"},
{"freddypharkas", "Freddy Pharkas: Frontier Pharmacist"},
{"hoyle4", "Hoyle Classic Card Games"},
+ {"inndemo", "ImagiNation Network (INN) Demo"},
{"kq6", "King's Quest VI: Heir Today, Gone Tomorrow"},
{"laurabow2", "Laura Bow 2: The Dagger of Amon Ra"},
{"qfg1vga", "Quest for Glory I: So You Want to Be a Hero"}, // Note: There was also a SCI0 version of this (further up)
@@ -98,11 +99,15 @@ static const PlainGameDescriptor s_sciGameTitles[] = {
{"lsl6", "Leisure Suit Larry 6: Shape Up or Slip Out!"},
{"pepper", "Pepper's Adventure in Time"},
{"slater", "Slater & Charlie Go Camping"},
+ {"gk1demo", "Gabriel Knight: Sins of the Fathers"},
+ {"qfg4demo", "Quest for Glory IV: Shadows of Darkness"},
+ {"pq4demo", "Police Quest IV: Open Season"},
// === SCI2 games =========================================================
- {"gk1", "Gabriel Knight: Sins of the Fathers"}, // demo is SCI11, full version SCI32
+ {"gk1", "Gabriel Knight: Sins of the Fathers"},
{"pq4", "Police Quest IV: Open Season"}, // floppy is SCI2, CD SCI2.1
{"qfg4", "Quest for Glory IV: Shadows of Darkness"}, // floppy is SCI2, CD SCI2.1
// === SCI2.1 games ========================================================
+ {"hoyle5", "Hoyle Classic Games"},
{"chest", "Inside the Chest"}, // aka Behind the Developer's Shield
{"gk2", "The Beast Within: A Gabriel Knight Mystery"},
{"kq7", "King's Quest VII: The Princeless Bride"},
@@ -146,13 +151,16 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = {
{ "fairytales", GID_FAIRYTALES },
{ "freddypharkas", GID_FREDDYPHARKAS },
{ "funseeker", GID_FUNSEEKER },
+ { "gk1demo", GID_GK1DEMO },
{ "gk1", GID_GK1 },
{ "gk2", GID_GK2 },
{ "hoyle1", GID_HOYLE1 },
{ "hoyle2", GID_HOYLE2 },
{ "hoyle3", GID_HOYLE3 },
{ "hoyle4", GID_HOYLE4 },
+ { "hoyle5", GID_HOYLE5 },
{ "iceman", GID_ICEMAN },
+ { "inndemo", GID_INNDEMO },
{ "islandbrain", GID_ISLANDBRAIN },
{ "jones", GID_JONES },
{ "kq1sci", GID_KQ1 },
@@ -183,12 +191,14 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = {
{ "pq2", GID_PQ2 },
{ "pq3", GID_PQ3 },
{ "pq4", GID_PQ4 },
+ { "pq4demo", GID_PQ4DEMO },
{ "pqswat", GID_PQSWAT },
{ "qfg1", GID_QFG1 },
{ "qfg1vga", GID_QFG1VGA },
{ "qfg2", GID_QFG2 },
{ "qfg3", GID_QFG3 },
{ "qfg4", GID_QFG4 },
+ { "qfg4demo", GID_QFG4DEMO },
{ "rama", GID_RAMA },
{ "sci-fanmade", GID_FANMADE }, // FIXME: Do we really need/want this?
{ "shivers", GID_SHIVERS },
@@ -356,7 +366,7 @@ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, R
// qfg4 demo has less than 50 scripts
if (resources.size() < 50)
- return "qfg4";
+ return "qfg4demo";
// Otherwise it's qfg3
return "qfg3";
@@ -389,6 +399,16 @@ static const ADExtraGuiOptionsMap optionsList[] = {
},
{
+ GAMEOPTION_ENABLE_BLACK_LINED_VIDEO,
+ {
+ _s("Enable black-lined video"),
+ _s("Draw black lines over videos to increase their apparent sharpness"),
+ "enable_black_lined_video",
+ false
+ }
+ },
+
+ {
GAMEOPTION_PREFER_DIGITAL_SFX,
{
_s("Prefer digital sound effects"),
@@ -473,7 +493,7 @@ static char s_fallbackGameIdBuf[256];
class SciMetaEngine : public AdvancedMetaEngine {
public:
SciMetaEngine() : AdvancedMetaEngine(Sci::SciGameDescriptions, sizeof(ADGameDescription), s_sciGameTitles, optionsList) {
- _singleid = "sci";
+ _singleId = "sci";
}
virtual const char *getName() const {
@@ -526,8 +546,8 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
s_fallbackDesc.language = Common::EN_ANY;
s_fallbackDesc.flags = ADGF_NO_FLAGS;
s_fallbackDesc.platform = Common::kPlatformDOS; // default to PC platform
- s_fallbackDesc.gameid = "sci";
- s_fallbackDesc.guioptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);
+ s_fallbackDesc.gameId = "sci";
+ s_fallbackDesc.guiOptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);
if (allFiles.contains("resource.map") || allFiles.contains("Data1")
|| allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) {
@@ -610,7 +630,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0; // Make sure string is NULL terminated
- s_fallbackDesc.gameid = s_fallbackGameIdBuf;
+ s_fallbackDesc.gameId = s_fallbackGameIdBuf;
// Try to determine the game language
// Load up text 0 and start looking for "#" characters
@@ -653,7 +673,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
const bool isCD = (s_fallbackDesc.flags & ADGF_CD);
if (!isCD)
- s_fallbackDesc.guioptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);
+ s_fallbackDesc.guiOptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);
if (gameId.hasSuffix("sci")) {
s_fallbackDesc.extra = "SCI";
@@ -686,7 +706,7 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles,
bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
const GameIdStrToEnum *g = s_gameIdStrToEnum;
for (; g->gameidStr; ++g) {
- if (0 == strcmp(desc->gameid, g->gameidStr)) {
+ if (0 == strcmp(desc->gameId, g->gameidStr)) {
*engine = new SciEngine(syst, desc, g->gameidEnum);
return true;
}
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index 2fd433240b..f205609e20 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -30,6 +30,7 @@ namespace Sci {
#define GAMEOPTION_SQ4_SILVER_CURSORS GUIO_GAMEOPTIONS6
#define GAMEOPTION_EGA_UNDITHER GUIO_GAMEOPTIONS7
#define GAMEOPTION_HIGH_RESOLUTION_GRAPHICS GUIO_GAMEOPTIONS8
+#define GAMEOPTION_ENABLE_BLACK_LINED_VIDEO GUIO_GAMEOPTIONS9
// SCI3 games have a different script format (in CSC files) and are currently unsupported
#define ENABLE_SCI3_GAMES
@@ -239,6 +240,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Codename: Iceman - English Atari ST
+ // Game version 1.041
+ // Executable reports "1.002.041"
+ { "iceman", "",{
+ { "resource.map", 0, "066e89b685ad788e06bae0b76d0d37d3", 5718 },
+ { "resource.000", 0, "053278385ce910a3f630f2e45e3c10be", 26987 },
+ { "resource.001", 0, "32b351072fccf76fc82234d73d28c08b", 438880 },
+ { "resource.002", 0, "36670a917550757d57df84c96cf9e6d9", 566667 },
+ { "resource.003", 0, "d97a96f1ab91b41cf46a02cc89b0a04e", 624304 },
+ { "resource.004", 0, "8613c45fc771d658e5a505b9a4a54f31", 670884 },
+ AD_LISTEND },
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Codename: Iceman - English DOS Non-Interactive Demo
// Executable scanning reports "0.000.685"
{"iceman", "Demo", {
@@ -336,6 +350,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Conquests of Camelot - English Atari ST
+ // Game version 1.019.000
+ // Floppy: INT#10.12.90
+ // Executable reports "1.002.038"
+ {"camelot", "", {
+ {"resource.map", 0, "0f80a11867be91a158823887a49cf443", 7290},
+ {"resource.001", 0, "162f66c42e4146ee63f78fba6f1a6757", 596773},
+ {"resource.002", 0, "162f66c42e4146ee63f78fba6f1a6757", 724615},
+ {"resource.003", 0, "162f66c42e4146ee63f78fba6f1a6757", 713351},
+ {"resource.004", 0, "162f66c42e4146ee63f78fba6f1a6757", 718766},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Conquests of Camelot - English DOS
// SCI interpreter version 0.000.685
{"camelot", "", {
@@ -684,30 +711,41 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // Gabriel Knight - English DOS CD Demo
+ // Gabriel Knight - English DOS Demo
// SCI interpreter version 1.001.092
- {"gk1", "CD Demo", {
+ // Note: we are not using ADGF_DEMO here, to avoid a game ID like gk1demo-demo
+ {"gk1demo", "Demo", {
{"resource.map", 0, "39645952ae0ed8072c7e838f31b75464", 2490},
{"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
- // Gabriel Knight - English DOS CD Demo (from DrMcCoy)
+ // Gabriel Knight - English DOS Demo (from DrMcCoy)
// SCI interpreter version 1.001.092
- {"gk1", "CD Demo", {
+ // Note: we are not using ADGF_DEMO here, to avoid a game ID like gk1demo-demo
+ {"gk1demo", "Demo", {
{"resource.map", 0, "8cad2a256f41463030cbb7ea1bfb2857", 2490},
{"resource.000", 0, "eb3ed7477ca4110813fe1fcf35928561", 1718450},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+#define GUIO_GK1_FLOPPY GUIO4(GUIO_NOSPEECH, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK1_CD GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK1_MAC GUIO_GK1_FLOPPY
+
// Gabriel Knight - English DOS Floppy
// SCI interpreter version 2.000.000
{"gk1", "", {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - English DOS Floppy (supplied my markcoolio in bug report #2723777)
// SCI interpreter version 2.000.000
@@ -715,7 +753,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "65e8c14092e4c9b3b3538b7602c8c5ec", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - English DOS Floppy
// SCI interpreter version 2.000.000, VERSION file reports "1.0\nGabriel Knight\n11/22/10:33 pm\n\x1A"
@@ -723,7 +761,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "ef41df08cf2c1f680216cdbeed0f8311", 10783},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 13022630},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - German DOS Floppy (supplied my markcoolio in bug report #2723775)
// SCI interpreter version 2.000.000
@@ -731,7 +769,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "ad6508b0296b25c07b1f58828dc33696", 10789},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13077029},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - French DOS Floppy (supplied my kervala in bug report #3611487)
// SCI interpreter version 2.000.000
@@ -739,7 +777,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "236e36cc847cdeafdd5e5fa8cba916ed", 10801},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13033072},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK1_FLOPPY },
// Gabriel Knight - English DOS CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "01.100.000"
@@ -747,7 +785,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - English Windows CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "01.100.000"
@@ -755,7 +793,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "372d059f75856afa6d73dd84cbb8913d", 10996},
{"resource.000", 0, "69b7516962510f780d38519cc15fcc7c", 12581736},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO5(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - German DOS CD (from Tobis87)
// SCI interpreter version 2.000.000
@@ -763,7 +801,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - Spanish DOS CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "1.000.000, April 13, 1995"
@@ -771,7 +809,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - French DOS CD (from Hkz)
// VERSION file reports "1.000.000, May 3, 1994"
@@ -779,7 +817,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "55f909ba93a2515042a08d8a2da8414e", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13325145},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - German Windows CD (from Tobis87)
// SCI interpreter version 2.000.000
@@ -787,7 +825,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a7d3e55114c65647310373cb390815ba", 11392},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13400497},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO5(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - Spanish Windows CD (from jvprat)
// Executable scanning reports "2.000.000", VERSION file reports "1.000.000, April 13, 1995"
@@ -795,7 +833,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "7cb6e9bba15b544ec7a635c45bde9953", 11404},
{"resource.000", 0, "091cf08910780feabc56f8551b09cb36", 13381599},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO5(GUIO_NOASPECT, GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformWindows, ADGF_CD | ADGF_UNSTABLE, GUIO_GK1_CD },
// Gabriel Knight - English Macintosh
{"gk1", "", {
@@ -804,7 +842,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"Data3", 0, "f25068b408b09275d8b698866462f578", 3677599},
{"Data4", 0, "1cceebbe411b26c860a74f91c337fdf3", 3230086},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO_GK1_MAC },
+
+#define GUIO_GK2_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK2 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_GK2_MAC GUIO_GK2
// Gabriel Knight 2 - English Windows Non-Interactive Demo
// Executable scanning reports "2.100.002"
@@ -812,7 +862,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "e0effce11c4908f4b91838741716c83d", 1351},
{"resource.000", 0, "d04cfc7f04b6f74d13025378be49ec2b", 4640330},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_GK2_DEMO },
// Gabriel Knight 2 - English DOS (GOG version) - ressci.* merged in ressci.000
// using Enrico Rolfi's HD/DVD installer: http://gkpatches.vogons.zetafleet.com/
@@ -820,7 +870,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "b996fa1e57389a1e179a00a0049de1f4", 8110},
{"ressci.000", 0, "a19fc3604c6e5407abcf03d59ee87217", 168522221},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK2 },
// Gabriel Knight 2 - English DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.1"
@@ -838,7 +888,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.006", 0, "ce9359037277b7d7976da185c2fa0aad", 2977},
{"ressci.006", 0, "8e44e03890205a7be12f45aaba9644b4", 60659424},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK2 },
// Gabriel Knight 2 - French DOS (6-CDs Sierra Originals reedition)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -856,7 +906,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.006", 0, "11b2e722170b8c93fdaa5428e2c7676f", 3001},
{"ressci.006", 0, "4037d941aec39d2e654e20960429aefc", 60568486},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_GK2 },
// Gabriel Knight 2 - English Macintosh
// NOTE: This only contains disc 1 files (as well as the persistent file:
@@ -868,7 +918,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"Data4", 0, "8b843c62eb53136a855d6e0087e3cb0d", 5889553},
{"Data5", 0, "f9fcf9ab2eb13b2125c33a1cda03a093", 14349984},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO_GK2_MAC },
#endif // ENABLE_SCI32
@@ -924,6 +974,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Hoyle 1 - English Atari ST
+ // Game version 1.000.104, SCI interpreter version 1.002.024
+ {"hoyle1", "", {
+ {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 518127},
+ {"resource.map", 0, "0af9a3dcd72a091960de070432e1f524", 4386},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
+ // Hoyle 1 - English Atari ST
+ // Game version 1.000.108, SCI interpreter version 1.002.026
+ {"hoyle1", "", {
+ {"resource.map", 0, "ed8355f84752e49ffa1f0cf9eca4b28e", 4140},
+ {"resource.001", 0, "e0dd44069a62a463fd124974b915f10d", 517454},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Hoyle 2 - English DOS
// SCI interpreter version 0.000.572
{"hoyle2", "", {
@@ -941,6 +1007,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Hoyle 2 - English DOS (supplied by m_kiewitz)
+ // SCI interpreter version 0.000.668, Ver 1.000.014, 2x5.25"
+ {"hoyle2", "", {
+ {"resource.map", 0, "8cef06c93d17d96f44aacd5902d84b30", 2100},
+ {"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 98289},
+ {"resource.002", 0, "8f2dd70abe01112eca464cda818b5eb6", 197326},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Hoyle 2 - English DOS (supplied by misterhands in bug report #6598)
// Game v1.000.016, interpreter 0.000.668, INT #12.5.90
{"hoyle2", "", {
@@ -958,6 +1033,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Hoyle 2 - English Atari ST
+ // Game version 1.001.017
+ // Executable scanning reports "1.002.034"
+ {"hoyle2", "", {
+ {"resource.map", 0, "13c8cc977598b6ad61d24c6296a090fd", 1356},
+ {"resource.001", 0, "8f2dd70abe01112eca464cda818b5eb6", 216280},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Hoyle 2 - English Macintosh
// Executable scanning reports "x.yyy.zzz"
{"hoyle2", "", {
@@ -1048,6 +1132,28 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+#ifdef ENABLE_SCI32
+#define GUIO_HOYLE5_DEMO GUIO3(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+
+ // Hoyle 5 (Hoyle Classic Games) - Windows demo
+ {"hoyle5", "Demo", {
+ {"ressci.000", 0, "98a39ae535dd01714ac313f8ba925045", 7260363},
+ {"resmap.000", 0, "10267a1542a73d527e50f0340549088b", 4900},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_HOYLE5_DEMO },
+
+#endif // ENABLE_SCI32
+
+ // ImagiNation Network (INN) Demo
+ // SCI interpreter version 1.001.097
+ {"inndemo", "", {
+ {"resource.000", 0, "535b1b920441ec73f42eaa4ccfd47b89", 514578},
+ {"resource.map", 0, "333daf27c3e8a6d274a3e0061ed7cd5c", 1545},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Jones in the Fast Lane EGA - English DOS
// SCI interpreter version 1.000.172 (not 100% sure FIXME)
{"jones", "EGA", {
@@ -1639,14 +1745,15 @@ static const struct ADGameDescription SciGameDescriptions[] = {
#ifdef ENABLE_SCI32
-
- // King's Quest 7 - English Windows (from abevi)
- // VERSION 1.65c
- {"kq7", "", {
- {"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195},
- {"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925},
- AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+#define GUIO_KQ7_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_KQ7 GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
// King's Quest 7 - English Windows (from the King's Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.4"
@@ -1654,7 +1761,34 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "2be9ab94429c721af8e05c507e048a15", 18697},
{"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 203882535},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
+
+ // King's Quest 7 - English Windows-interpreter-only (supplied by m_kiewitz)
+ // SCI interpreter version 2.100.002, VERSION file reports "1.51"
+ {"kq7", "", {
+ {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
+ {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
+ {"resource.aud", 0, "c2a988a16053eb98c7b73a75139902a0", 217716879},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
+
+ // King's Quest 7 - German Windows-interpreter-only (supplied by markcoolio in bug report #2727402)
+ // SCI interpreter version 2.100.002, VERSION file reports "1.51"
+ // same as English 1.51, only resource.aud/resource.sfx are different
+ {"kq7", "", {
+ {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
+ {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
+ {"resource.aud", 0, "3f17bcaf8a9ff6a6c2d4de1a2078fdcc", 258119621},
+ AD_LISTEND},
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
+
+ // King's Quest 7 - English Windows (from abevi)
+ // VERSION 1.65c
+ {"kq7", "", {
+ {"resource.000", 0, "4948e4e1506f1e1c4e1d47abfa06b7f8", 204385195},
+ {"resource.map", 0, "40ccafb2195301504eba2e4f4f2c7f3d", 18925},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English DOS (from FRG)
// SCI interpreter version 2.100.002, VERSION file reports "2.00b"
@@ -1662,7 +1796,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English Windows (from FRG)
// SCI interpreter version 2.100.002, VERSION file reports "2.00b"
@@ -1670,15 +1804,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "8676b0fbbd7362989a029fe72fea14c6", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-
- // King's Quest 7 - German Windows (supplied by markcoolio in bug report #2727402)
- // SCI interpreter version 2.100.002
- {"kq7", "", {
- {"resource.map", 0, "838b9ff132bd6962026fee832e8a7ddb", 18697},
- {"resource.000", 0, "eb63ea3a2c2469dc2d777d351c626404", 206626576},
- AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - Spanish DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "2.00"
@@ -1686,7 +1812,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "0b62693cbe87e3aaca3e8655a437f27f", 18709},
{"resource.000", 0, "51c1ead1163e19a2de8f121c39df7a76", 200764100},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7 },
// King's Quest 7 - English DOS Non-Interactive Demo
// SCI interpreter version 2.100.002
@@ -1694,7 +1820,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "b44f774108d63faa1d021101221c5a54", 1690},
{"resource.000", 0, "d9659d2cf0c269c6a9dc776707f5bea0", 2433827},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_KQ7_DEMO },
// King's Quest 7 - English Windows Demo (from DrMcCoy)
// SCI interpreter version 2.100.002
@@ -1702,7 +1828,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "38e627a37a975aea40cc72b0518b0709", 18412},
{"resource.000", 0, "bad61d50aaa64298fa57a7c6ccd3bccf", 84020382},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO_KQ7_DEMO },
// King's Questions mini-game from the King's Quest Collection
// SCI interpreter version 2.000.000
@@ -1942,6 +2068,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 2 - English Atari ST
+ // Game version 1.001.006
+ // Executable reports "1.000.159" 1988-12-02 12:22 p.m.
+ {"lsl2", "", {
+ {"resource.map", 0, "2fc3ce7da1346e4dadfee18606d814fc", 4758},
+ {"resource.001", 0, "4a24443a25e2b1492462a52809605dc2", 477342},
+ {"resource.002", 0, "4a24443a25e2b1492462a52809605dc2", 406698},
+ {"resource.003", 0, "4a24443a25e2b1492462a52809605dc2", 592433},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 2 - English DOS Non-Interactive Demo
// Executable scanning reports "x.yyy.zzz"
// SCI interpreter version 0.000.409
@@ -1999,6 +2136,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 2 - English Atari ST (Kixx)
+ // Game version 1.002.000
+ // Executable reports "1.001.008" 1989-01-12 16:30
+ {"lsl2", "", {
+ {"resource.map", 0, "2c9c3b0923e3764f5ab999bcb71c2d47", 4758},
+ {"resource.001", 0, "4a24443a25e2b1492462a52809605dc2", 477625},
+ {"resource.002", 0, "4a24443a25e2b1492462a52809605dc2", 406935},
+ {"resource.003", 0, "4a24443a25e2b1492462a52809605dc2", 592533},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 3 - English Amiga (from www.back2roots.org)
// Executable scanning reports "1.002.032"
// SCI interpreter version 0.000.685
@@ -2013,6 +2161,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Larry 3 - English Atari ST
+ // Game version 1.021, 1990-01-27
+ // Int#6.26.90
+ // Executable scanning reports "1.002.026"
+ {"lsl3", "", {
+ {"resource.map", 0, "0b6bd3e039682830a51c5755c06591db", 5916},
+ {"resource.001", 0, "f18441027154292836b973c655fa3175", 456722},
+ {"resource.002", 0, "f18441027154292836b973c655fa3175", 578024},
+ {"resource.003", 0, "f18441027154292836b973c655fa3175", 506807},
+ {"resource.004", 0, "f18441027154292836b973c655fa3175", 513651},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Larry 3 - English DOS (supplied by ssburnout in bug report #3049193)
// 1.021 8x5.25" (label: Int#5.15.90)
{"lsl3", "", {
@@ -2357,13 +2518,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_LSL6HIRES GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Larry 6 - English/German DOS CD - HIRES
// SCI interpreter version 2.100.002
{"lsl6hires", "Hi-res", {
{"resource.map", 0, "0c0804434ea62278dd15032b1947426c", 8872},
{"resource.000", 0, "9a9f4870504444cda863dd14d077a680", 18520872},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL6HIRES },
// Larry 6 - German DOS CD - HIRES (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
@@ -2371,7 +2538,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "badfdf446ffed569a310d2c63a249421", 8896},
{"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18534274},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL6HIRES },
// Larry 6 - French DOS CD - HIRES (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
@@ -2379,7 +2546,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "d184e9aa4f2d4b5670ddb3669db82cda", 8896},
{"resource.000", 0, "bd944d2b06614a5b39f1586906f0ee88", 18538987},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL6HIRES },
+
+#define GUIO_LSL7_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_LSL7 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
// Larry 7 - English DOS Demo (provided by richiefs in bug report #2670691)
// SCI interpreter version 2.100.002
@@ -2387,7 +2565,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "5cc6159688b2dc03790a67c90ccc67f9", 10195878},
{"resmap.000", 0, "6a2b2811eef82e87cde91cf1de845af8", 2695},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_LSL7_DEMO },
#ifdef ENABLE_SCI3_GAMES
// Larry 7 - English DOS CD (from spookypeanut)
@@ -2396,7 +2574,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "eae93e1b1d1ccc58b4691c371281c95d", 8188},
{"ressci.000", 0, "89353723488219e25589165d73ed663e", 66965678},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - German DOS (from Tobis87)
// SCI interpreter version 3.000.000
@@ -2404,7 +2582,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "c11e6bfcfc2f2d05da47e5a7df3e9b1a", 8188},
{"ressci.000", 0, "a8c6817bb94f332ff498a71c8b47f893", 66971724},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - French DOS (provided by richiefs in bug report #2670691)
// SCI interpreter version 3.000.000
@@ -2412,7 +2590,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "4407849fd52fe3efb0c30fba60cd5cd4", 8206},
{"ressci.000", 0, "dc37c3055fffbefb494ff22b145d377b", 66964472},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - Italian DOS CD (from glorifindel)
// SCI interpreter version 3.000.000
@@ -2420,7 +2598,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "9852a97141f789413f29bf956052acdb", 8212},
{"ressci.000", 0, "440b9fed89590abb4e4386ed6f948ee2", 67140181},
AD_LISTEND},
- Common::IT_ITA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::IT_ITA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
// Larry 7 - Spanish DOS (from the Leisure Suit Larry Collection)
// Executable scanning reports "3.000.000", VERSION file reports "1.0s"
@@ -2428,16 +2606,28 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "8f3d603e1acc834a5d598b30cdfc93f3", 8188},
{"ressci.000", 0, "32792f9bc1bf3633a88b382bb3f6e40d", 67071418},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LSL7 },
#endif
+#define GUIO_LIGHTHOUSE_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_LIGHTHOUSE GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Lighthouse - English Windows Demo (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.00"
{"lighthouse", "Demo", {
{"resource.map", 0, "543124606352bfa5e07696ddf2a669be", 64},
{"resource.000", 0, "5d7714416b612463d750fb9c5690c859", 28952},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_LIGHTHOUSE_DEMO },
#ifdef ENABLE_SCI3_GAMES
// Lighthouse - English Windows Demo
@@ -2446,7 +2636,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "3bdee7a16926975a4729f75cf6b80a92", 1525},
{"ressci.000", 0, "3c585827fa4a82f4c04a56a0bc52ccee", 11494351},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
// Lighthouse - English DOS (from jvprat)
// Executable scanning reports "3.000.000", VERSION file reports "1.1"
@@ -2456,7 +2646,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.002", 0, "c68db5333f152fea6ca2dfc75cad8b34", 7573},
{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94628315},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
// Lighthouse - Japanese DOS (from m_kiewitz)
// Executable scanning reports "3.000.000", VERSION file reports "1.0C"
@@ -2466,7 +2656,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.002", 0, "723fc742c623d8933e5753a264324cb0", 7657},
{"ressci.002", 0, "175468431a979b9f317c294ce3bc1430", 94627469},
AD_LISTEND},
- Common::JA_JPN, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::JA_JPN, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
// Lighthouse - Spanish DOS (from jvprat)
// Executable scanning reports "3.000.000", VERSION file reports "1.1"
@@ -2476,7 +2666,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.002", 0, "e7dc85884a2417e2eff9de0c63dd65fa", 7630},
{"ressci.002", 0, "3c8d627c555b0e3e4f1d9955bc0f0df4", 94631127},
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_LIGHTHOUSE },
#endif // ENABLE_SCI3_GAMES
#endif // ENABLE_SCI32
@@ -2598,13 +2788,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::JA_JPN, Common::kPlatformFMTowns, ADGF_ADDENGLISH, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_MOTHERGOOSEHIRES GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Mixed-Up Mother Goose Deluxe - English Windows/DOS CD (supplied by markcoolio in bug report #2723810)
// Executable scanning reports "2.100.002"
{"mothergoosehires", "", {
{"resource.map", 0, "5159a1578c4306bfe070a3e4d8c2e1d3", 4741},
{"resource.000", 0, "1926925c95d82f0999590e93b02887c5", 15150768},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_MOTHERGOOSEHIRES },
// Mixed-Up Mother Goose Deluxe - Multilingual Windows CD (English/French/German/Spanish)
// Executable scanning reports "2.100.002"
@@ -2612,7 +2808,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "ef611af561898dcfea87846919ebf3eb", 4969},
{"ressci.000", 0, "227685bc59d90821978d330713e44a7a", 17205800},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_MOTHERGOOSEHIRES },
#endif // ENABLE_SCI32
// Ms. Astro Chicken - English DOS
@@ -2624,6 +2820,42 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_PHANTASMAGORIA_DEMO GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_PHANTASMAGORIA GUIO_PHANTASMAGORIA_DEMO
+#define GUIO_PHANTASMAGORIA_MAC GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
+ // Phantasmagoria - English DOS/Windows (from csnover)
+ // Windows executable scanning reports "2.100.002" - "Aug 06 1995"
+ // DOS executable scanning reports "2.100.002" - "May 24 1995"
+ // VERSION file reports "1.000.000"
+ {"phantasmagoria", "", {
+ {"resmap.001", 0, "43c395f312a190e67b90b2c1e93a79e2", 11518},
+ {"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612},
+ {"resmap.002", 0, "94f142cfe8ec4107b6a42876cb603ed0", 12058},
+ {"ressci.002", 0, "3aae6559aa1df273bc542d5ac6330d75", 71588691},
+ {"resmap.003", 0, "39e9abd4501b5b6168dd07379c0be753", 12334},
+ {"ressci.003", 0, "3aae6559aa1df273bc542d5ac6330d75", 73651084},
+ {"resmap.004", 0, "434f9704658229fef322c863d2422a9a", 12556},
+ {"ressci.004", 0, "3aae6559aa1df273bc542d5ac6330d75", 75811935},
+ {"resmap.005", 0, "3ff9b4f7301800825c0ed008e091205e", 12604},
+ {"ressci.005", 0, "3aae6559aa1df273bc542d5ac6330d75", 78814934},
+ {"resmap.006", 0, "27ad413313e2a3ec3c53250e7ff5b2d1", 12532},
+ {"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 77901360},
+ {"resmap.007", 0, "aa8175cfc93242af6f5e65bdceaafc0d", 7972},
+ //{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
+
// Phantasmagoria - English DOS (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.100.000UK"
{"phantasmagoria", "", {
@@ -2642,7 +2874,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.007", 0, "afbd16ea77869a720afa1c5371de107d", 7972},
//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 25859038},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - German DOS/Windows
// Windows executable scanning reports "unknown" - "Sep 19 1995 09:39:48"
@@ -2665,7 +2897,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.007", 0, "06309b8043aecb85bd507b15d16cb544", 7984},
//{"ressci.007", 0, "3aae6559aa1df273bc542d5ac6330d75", 26898681},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - French DOS
// Supplied by Kervala in bug #6574
@@ -2684,7 +2916,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.006", 0, "3aae6559aa1df273bc542d5ac6330d75", 85415107},
{"resmap.007", 0, "5633960bc106c39ca91d2d8fce18fd2d", 7984},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - English DOS Demo
// Executable scanning reports "2.100.002"
@@ -2692,7 +2924,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.001", 0, "416138651ea828219ca454cae18341a3", 11518},
{"ressci.001", 0, "3aae6559aa1df273bc542d5ac6330d75", 65844612},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_PHANTASMAGORIA_DEMO },
// Phantasmagoria - English DOS/Windows (GOG version) - ressci.* merged in ressci.000
// Windows executable scanning reports "2.100.002" - "Sep 19 1995 15:09:43"
@@ -2703,7 +2935,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "cd5967f9b9586e3380645961c0765be3", 116822037},
{"resmap.000", 0, "3cafc1c6a53945c1f3babbfd6380c64c", 16468},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA },
// Phantasmagoria - English Macintosh
// NOTE: This only contains disc 1 files (as well as the two persistent files:
@@ -2719,10 +2951,22 @@ static const struct ADGameDescription SciGameDescriptions[] = {
// Data8-12 are empty
{"Data13", 0, "6d2c450fca19a69b5af74ed5b03c0a17", 14923328},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE, GUIO_PHANTASMAGORIA_MAC },
#ifdef ENABLE_SCI3_GAMES
- // Phantasmagoria 2 - English Windows (from jvprat)
+
+#define GUIO_PHANTASMAGORIA2 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GUIO_NOMIDI, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+
+ // Some versions of Phantasmagoria 2 were heavily censored.
+ // Censored versions (data files are currently unknown to us): UK, Australia, first English release in Germany
+
+ // Phantasmagoria 2 - English Windows (from jvprat) - US release
+ // Note: Fully uncensored
+ //
// Executable scanning reports "3.000.000", VERSION file reports "001.0.06"
{"phantasmagoria2", "", {
{"resmap.001", 0, "0a961e135f4f7effb195158325856633", 1108},
@@ -2736,13 +2980,25 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.005", 0, "8bd5ceeedcbe16dfe55d1b90dcd4be84", 1942},
{"ressci.005", 0, "05f9fe2bee749659acb3cd2c90252fc5", 67905112},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 },
+
+ // Phantasmagoria 2 - English DOS (GOG version) (supplied by littleboy in patch #1360)
+ // Note: Fully uncensored, basically the US release, but ressci.* merged into ressci.000
+ //
+ // Executable scanning reports "3.000.000" - "Dec 07 1996 09:29:03"
+ // VERSION file reports "001.0.06"
+ {"phantasmagoria2", "", {
+ {"ressci.000", 0, "c54f26d9f43f908151263254b6d97053", 108134481},
+ {"resmap.000", 0, "de154a223a9ef4ea7358b76adc38ef5b", 2956},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 },
- // Phantasmagoria 2 - German DOS/Windows
+ // Phantasmagoria 2 - German DOS/Windows (supplied by AReim1982)
+ // Note: Fully uncensored, but one scene is missing probably because of a mastering error (Curtis + Therese meeting near water cooler)
+ //
// Windows executable scanning reports "unknown" - "Dec 07 1996 15:42:02"
// DOS executable scanning reports "unknown" - "Dec 07 1996 08:35:12"
// VERSION file reports "000.1.0vu" (HEX: 30 30 30 2E 31 00 2E 30 76 FA 0D 0A)
- // Supplied by AReim1982
{"phantasmagoria2", "", {
{"resmap.001", 0, "d62f48ff8bddb39503b97e33439482c9", 1114},
{"ressci.001", 0, "4ebc2b8455c74ad205ae592eec27313a", 24590716},
@@ -2755,17 +3011,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.005", 0, "2fc48a4a5a73b726994f189da51a8b2a", 1954},
{"ressci.005", 0, "e94005890d22dd3b7f605a2a7c025803", 68232146},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
-
- // Phantasmagoria 2 - English DOS (GOG version) - ressci.* merged in ressci.000
- // Executable scanning reports "3.000.000" - "Dec 07 1996 09:29:03"
- // VERSION file reports "001.0.06"
- // Supplied by littleboy in patch #3112884
- {"phantasmagoria2", "", {
- {"ressci.000", 0, "c54f26d9f43f908151263254b6d97053", 108134481},
- {"resmap.000", 0, "de154a223a9ef4ea7358b76adc38ef5b", 2956},
- AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PHANTASMAGORIA2 },
#endif // ENABLE_SCI3_GAMES
#endif // ENABLE_SCI32
@@ -2852,6 +3098,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Police Quest 2 - English Atari ST
+ // Game version 1.002.011 DS 1989-07-21
+ // Executable reports "1.002.003"
+ {"pq2", "", {
+ {"resource.map", 0, "28a6f471c7900c2c92da40eecb615d9d", 4584},
+ {"resource.001", 0, "77f02def3094af804fd2371db25b7100", 509525},
+ {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 546000},
+ {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 591851},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Police Quest 2 - English DOS (from FRG)
// SCI interpreter version 0.000.395
{"pq2", "", {
@@ -2871,6 +3128,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Police Quest 2 - English Atari ST
+ // Game version 1.001.006 1989-01-16 13:30
+ // Executable reports "1.001.009"
+ {"pq2", "", {
+ {"resource.map", 0, "8e1161c684b342742d30f938a4839a4b", 4518},
+ {"resource.001", 0, "77f02def3094af804fd2371db25b7100", 506563},
+ {"resource.002", 0, "77f02def3094af804fd2371db25b7100", 541261},
+ {"resource.003", 0, "77f02def3094af804fd2371db25b7100", 587511},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Police Quest 2 - Japanese PC-98 (also includes english language)
// Executable scanning reports "x.yyy.zzz"
// SCI interpreter version unknown
@@ -2967,20 +3235,31 @@ static const struct ADGameDescription SciGameDescriptions[] = {
// Police Quest 4 - English DOS Non-Interactive Demo (from FRG)
// SCI interpreter version 1.001.096
- {"pq4", "Demo", {
+ // Note: we are not using ADGF_DEMO here, to avoid a game ID like pq4demo-demo
+ {"pq4demo", "Demo", {
{"resource.map", 0, "be56f87a1c4a13062a30a362df860c2f", 1472},
{"resource.000", 0, "527d5684016e6816157cd15d9071b11b", 1121310},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_PQ4_FLOPPY GUIO4(GUIO_NOSPEECH, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_PQ4_CD GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Police Quest 4 - English DOS CD (from the Police Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.100.000"
{"pq4", "CD", {
{"resource.map", 0, "379dfe80ed6bd16c47e4b950c4722eac", 11374},
{"resource.000", 0, "fd316a09b628b7032248139003369022", 18841068},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_PQ4_CD },
// Police Quest 4 - German DOS CD (German text, English speech)
// Supplied by markcoolio in bug report #3392955
@@ -2988,7 +3267,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "a398076371ed0e1e706c8f9fb9fc7ac5", 11386},
{"resource.000", 0, "6ff21954e0a2c5992279e7eb787c8d56", 18918747},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_PQ4_CD },
// Police Quest 4 - English DOS
// SCI interpreter version 2.000.000 (a guess?)
@@ -2996,7 +3275,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "aed9643158ccf01b71f359db33137f82", 9895},
{"resource.000", 0, "da383857b3be1e4514daeba2524359e0", 15141432},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQ4_FLOPPY },
// Police Quest 4 - French DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 2.000.000
@@ -3004,7 +3283,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "008030846edcc7c5c7a812c7f4ae4ceb", 9256},
{"resource.000", 0, "6ba98bd2e436739d87ecd2a9b99cabb4", 14730153},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQ4_FLOPPY },
// Police Quest 4 - German DOS (supplied by markcoolio in bug report #2723840)
// SCI interpreter version 2.000.000 (a guess?)
@@ -3012,7 +3291,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "2393ee728ab930b2762cb5889f9b5aff", 9256},
{"resource.000", 0, "6ba98bd2e436739d87ecd2a9b99cabb4", 14730155},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQ4_FLOPPY },
+
+#define GUIO_PQSWAT_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_PQSWAT GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
// Police Quest: SWAT - English DOS/Windows Demo (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "0.001.200"
@@ -3020,7 +3310,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "8c96733ef94c21526792f7ca4e3f2120", 1648},
{"resource.000", 0, "d8892f1b8c56c8f7704325460f49b300", 3676175},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_PQSWAT_DEMO },
// Police Quest: SWAT - English DOS (from GOG.com)
// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
@@ -3028,7 +3318,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "1c2563fee189885e29d9348f37306d94", 12175},
{"ressci.000", 0, "b2e1826ca81ce2e7e764587f5a14eee9", 127149181},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_PQSWAT },
// Police Quest: SWAT - English Windows (from the Police Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0c"
@@ -3043,7 +3333,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.004", 0, "4228038906f041623e65789500b22285", 6835},
{"ressci.004", 0, "b7e619e6ecf62fe65d5116a3a422e5f0", 46223872},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_PQSWAT },
#endif // ENABLE_SCI32
// Quest for Glory 1 / Hero's Quest - English DOS 3.5" Floppy (supplied by merkur in bug report #2718784)
@@ -3139,6 +3429,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformDOS, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Quest for Glory 1 / Hero's Quest - English Atari ST
+ // Game version 1.137
+ // Executable reports "1.002.028"
+ {"qfg1", "", {
+ {"resource.map", 0, "2a794066ad161acbedac8fa14e46905d", 6438},
+ {"resource.000", 0, "40332d3ebfc70a4b6a6a0443c2763287", 79204},
+ {"resource.001", 0, "f7fc269d3db146830d6427d3e02d4187", 473547},
+ {"resource.002", 0, "e64004e020fdf1813be52b639b08be89", 635687},
+ {"resource.003", 0, "f0af87c60ec869946da442833aa5afa8", 640438},
+ {"resource.004", 0, "f0af87c60ec869946da442833aa5afa8", 644452},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Quest for Glory 1 / Hero's Quest - English DOS Demo
// Executable scanning reports "0.000.685"
{"qfg1", "Demo", {
@@ -3218,6 +3521,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Quest for Glory 2 - English Amiga
+ // Game version 1.109
// Executable scanning reports "1.003.004"
// SCI interpreter version 0.001.010
{"qfg2", "", {
@@ -3379,20 +3683,30 @@ static const struct ADGameDescription SciGameDescriptions[] = {
// Quest for Glory 4 - English DOS Non-Interactive Demo (from FRG)
// SCI interpreter version 1.001.069 (just a guess)
- {"qfg4", "Demo", {
+ // Note: we are not using ADGF_DEMO here, to avoid a game ID like qfg4demo-demo
+ {"qfg4demo", "Demo", {
{"resource.map", 0, "1ba7c7ae1efb315326d45cb931569b1b", 922},
{"resource.000", 0, "41ba03f0b188b029132daa3ece0d3e14", 623154},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_QFG4_FLOPPY GUIO4(GUIO_NOSPEECH, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_QFG4_CD GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Quest for Glory 4 1.1 Floppy - English DOS (supplied by markcool in bug report #2723852)
// SCI interpreter version 2.000.000 (a guess?)
{"qfg4", "", {
{"resource.map", 0, "685bdb1ed47bbbb0e5e25db392da83ce", 9301},
{"resource.000", 0, "f64fd6aa3977939a86ff30783dd677e1", 11004993},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_QFG4_FLOPPY },
// Quest for Glory 4 1.1 Floppy - English DOS (supplied by abevi in bug report #2612718)
// SCI interpreter version 2.000.000
@@ -3400,7 +3714,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "d10a4cc177d2091d744e2ad8c049b0ae", 9295},
{"resource.000", 0, "f64fd6aa3977939a86ff30783dd677e1", 11003589},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_QFG4_FLOPPY },
// Quest for Glory 4 1.1 Floppy - German DOS (supplied by markcool in bug report #2723850)
// Executable scanning reports "2.000.000", VERSION file reports "1.1"
@@ -3408,7 +3722,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "9e0abba8746f40565bc7eb5720522ecd", 9301},
{"resource.000", 0, "57f22cdc54eeb35fce1f26b31b5c3ee1", 11076197},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO_QFG4_FLOPPY },
// Quest for Glory 4 CD - English DOS/Windows (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -3416,7 +3730,14 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "aba367f2102e81782d961b14fbe3d630", 10246},
{"resource.000", 0, "263dce4aa34c49d3ad29bec889007b1c", 11571394},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_QFG4_CD },
+
+#define GUIO_RAMA_DEMO GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_RAMA GUIO_RAMA_DEMO
// RAMA - English DOS/Windows Demo
// Executable scanning reports "2.100.002", VERSION file reports "000.000.008"
@@ -3424,7 +3745,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.001", 0, "775304e9b2a545156be4d94209550094", 1393},
{"ressci.001", 0, "259437fd75fdf51e8207fda8c01fa4fd", 2334384},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_RAMA_DEMO },
#ifdef ENABLE_SCI3_GAMES
// RAMA - English Windows (from jvprat)
@@ -3437,7 +3758,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.003", 0, "31ef4c0621711585d031f0ae81707251", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6860492},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
// RAMA - English Windows (from Quietust, in bug report #2850645)
{"rama", "", {
@@ -3448,7 +3769,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.003", 0, "48841e4b84ef1b98b48d43566fda9e13", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6870356},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
// RAMA - German Windows CD (from farmboy0, in pull request 397)
{"rama", "", {
@@ -3459,7 +3780,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.003", 0, "222096000bd83a1d56577114a452cccf", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6954219},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
// RAMA - Italian Windows CD (from glorifindel)
// SCI interpreter version 3.000.000 (a guess?)
@@ -3467,23 +3788,29 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.001", 0, "2a68edd064e5e4937b5e9c74b38f2082", 70611091},
{"resmap.001", 0, "70ba2ff04a2b7fb2c52420ba7fbd47c2", 8338},
AD_LISTEND},
- Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_RAMA },
#endif // ENABLE_SCI3_GAMES
+#define GUIO_SHIVERS_DEMO GUIO4(GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_SHIVERS GUIO_SHIVERS_DEMO
+
// Shivers - English Windows (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.02"
{"shivers", "", {
{"resmap.000", 0, "f2ead37749ed8f6535a2445a7d05a0cc", 46525},
{"ressci.000", 0, "4294c6d7510935f2e0a52e302073c951", 262654836},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_SHIVERS },
// Shivers - German Windows (from Tobis87)
{"shivers", "", {
{"resmap.000", 0, "f483d0a1f78334c18052e92785c3086e", 46537},
{"ressci.000", 0, "6751b144671e2deed919eb9d284b07eb", 262390692},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO_SHIVERS },
// Shivers - English Windows Demo
// Executable scanning reports "2.100.002"
@@ -3491,7 +3818,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "d9e0bc5eddefcbe47f528760085d8927", 1186},
{"ressci.000", 0, "3a93c6340b54e07e65d0e5583354d186", 10505469},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO_SHIVERS },
// Shivers 2 doesn't contain SCI scripts. The whole game logic has
// been reimplemented from SCI in native code placed in DLL files.
@@ -3509,7 +3836,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "d8659188b84beaef076bd869837cd530", 634},
{"ressci.000", 0, "7fbac0807a044c9543e8ac376d200e59", 4925003},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// Shivers 2 - English Windows (from abevi)
// VERSION.TXT Version 1.0 (3/25/97)
@@ -3517,7 +3844,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.001", 0, "a79d03d6eb75be0a79324f14e3d2ace4", 95346793},
{"resmap.001", 0, "a4804d436d90c4ec2e46b537f5e954db", 6268},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO6(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#endif
@@ -3639,6 +3966,18 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformAmiga, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Space Quest 3 - English Atari ST
+ // Game version 1.0Q 1989-27-03 17:00
+ // Int#1.002.002
+ // Executable reports "1.002.001"
+ {"sq3", "", {
+ {"resource.map", 0, "c36e322805949affd882a75803a6a54e", 5484},
+ {"resource.001", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 485146},
+ {"resource.002", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 720227},
+ {"resource.003", 0, "ceeda7202b96e5c85ecaa88a40a540fc", 688524},
+ AD_LISTEND},
+ Common::EN_ANY, Common::kPlatformAtariST, 0, GUIO5(GUIO_NOSPEECH, GAMEOPTION_EGA_UNDITHER, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Space Quest 3 - German Amiga (also includes english language)
// Executable scanning reports "1.004.006"
// SCI interpreter version 0.000.453 (just a guess)
@@ -4037,13 +4376,25 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::RU_RUS, Common::kPlatformDOS, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_SQ6_DEMO GUIO5(GUIO_NOSPEECH, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+#define GUIO_SQ6 GUIO5(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GAMEOPTION_PREFER_DIGITAL_SFX, \
+ GAMEOPTION_ORIGINAL_SAVELOAD, \
+ GAMEOPTION_FB01_MIDI)
+
// Space Quest 6 - English DOS/Win3.11 CD (from the Space Quest Collection)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
{"sq6", "", {
{"resource.map", 0, "6dddfa3a8f3a3a513ec9dfdfae955005", 10528},
{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - English DOS/Win3.11 CD ver 1.11 (from FRG)
// SCI interpreter version 2.100.002 (just a guess)
@@ -4051,7 +4402,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "e0615d6e4e10e37ae42e6a2a95aaf145", 10528},
{"resource.000", 0, "c4259ab7355aead07773397b1052827d", 41150806},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - French DOS/Win3.11 CD (from French magazine Joystick - September 1997)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -4059,7 +4410,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "3c831625931d5079b73ae8c275f52c95", 10534},
{"resource.000", 0, "4195ca940f759424f62b90e262cc1737", 40932397},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - German DOS (from Tobis87, updated info from markcoolio in bug report #2723884)
// SCI interpreter version 2.100.002 (just a guess)
@@ -4067,7 +4418,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "664d797415484f85c90b1b45aedc7686", 10534},
{"resource.000", 0, "ba87ba91e5bdabb4169dd0df75777722", 40933685},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformDOS, ADGF_CD | ADGF_UNSTABLE, GUIO_SQ6 },
// Space Quest 6 - English DOS/Win3.11 Interactive Demo (from FRG)
// SCI interpreter version 2.100.002 (just a guess)
@@ -4075,7 +4426,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resource.map", 0, "368f07b07433db3f819fa3fa0e5efee5", 2572},
{"resource.000", 0, "ab12724e078dea34b624e0d2a38dcd7c", 2272050},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO | ADGF_UNSTABLE, GUIO_SQ6_DEMO },
#endif // ENABLE_SCI32
// The Island of Dr. Brain - English DOS CD (from jvprat)
@@ -4103,13 +4454,23 @@ static const struct ADGameDescription SciGameDescriptions[] = {
Common::EN_ANY, Common::kPlatformDOS, ADGF_DEMO, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
#ifdef ENABLE_SCI32
+
+#define GUIO_TORIN_DEMO GUIO3(GUIO_NOASPECT, \
+ GUIO_NOMIDI, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+#define GUIO_TORIN GUIO4(GAMEOPTION_ENABLE_BLACK_LINED_VIDEO, \
+ GUIO_NOASPECT, \
+ GUIO_NOMIDI, \
+ GAMEOPTION_ORIGINAL_SAVELOAD)
+#define GUIO_TORIN_MAC GUIO_TORIN
+
// Torin's Passage - English Windows Interactive Demo
// SCI interpreter version 2.100.002
{"torin", "Demo", {
{"resmap.000", 0, "9a3e172cde9963d0a969f26469318cec", 3403},
{"ressci.000", 0, "db3e290481c35c3224e9602e71e4a1f1", 5073868},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN_DEMO },
// Torin's Passage (Multilingual) - English Windows CD
// SCI interpreter version 2.100.002
@@ -4117,7 +4478,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - Spanish Windows CD (from jvprat)
// Executable scanning reports "2.100.002", VERSION file reports "1.0"
@@ -4126,7 +4487,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
// TODO: depend on one of the patches?
AD_LISTEND},
- Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::ES_ESP, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - French Windows CD
// SCI interpreter version 2.100.002
@@ -4134,7 +4495,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - German Windows CD (from m_kiewitz)
// SCI interpreter version 2.100.002
@@ -4143,7 +4504,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "e55c3097329b3c53752301e01c6af2fb", 9787},
{"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56127540},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - German Windows CD
// SCI interpreter version 2.100.002
@@ -4151,7 +4512,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage (Multilingual) - Italian Windows CD (from glorifindel)
// SCI interpreter version 2.100.002
@@ -4159,7 +4520,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "bb3b0b22ff08df54fbe2d06263409be6", 9799},
{"ressci.000", 0, "693a259d346c9360f4a0c11fdaae430a", 55973887},
AD_LISTEND},
- Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::IT_ITA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - French Windows (from LePhilousophe)
// SCI interpreter version 2.100.002
@@ -4167,7 +4528,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"resmap.000", 0, "66ed46e3e56f487e688d52f05b33d0ba", 9787},
{"ressci.000", 0, "118f9bec04bfe17c4f87bbb5ddb43c18", 56126981},
AD_LISTEND},
- Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::FR_FRA, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
+
+ // Torin's Passage - Russian Windows CD (SoftClub official translate)
+ // SCI interpreter version 2.100.002
+ // VERSION file "1.0"
+ { "torin", "",{
+ { "resource.aud", 0, "f66df699be5ed011b16b3f816cee8a04", 210583510 },
+ { "ressci.000", 0, "e672da099fb1663b87c78abc6c8ba2a4", 130622695 },
+ { "resmap.000", 0, "643859f8f2be8e7701611e29b3b65208", 9799 },
+ AD_LISTEND },
+ Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN },
// Torin's Passage - English Macintosh
{"torin", "", {
@@ -4179,7 +4550,7 @@ static const struct ADGameDescription SciGameDescriptions[] = {
{"Data6", 0, "b639487c83d1dae0e001e700f3631566", 7594881},
{"Data7", 0, "2afd9b5434102b89610916b904c3f73a", 7627374},
AD_LISTEND},
- Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE | ADGF_CD, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ Common::EN_ANY, Common::kPlatformMacintosh, ADGF_MACRESFORK | ADGF_UNSTABLE | ADGF_CD, GUIO_TORIN_MAC },
#endif // ENABLE_SCI32
// SCI Fanmade Games
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp
index 0b1001bfda..156f6f51f7 100644
--- a/engines/sci/engine/file.cpp
+++ b/engines/sci/engine/file.cpp
@@ -22,6 +22,7 @@
#include "common/savefile.h"
#include "common/stream.h"
+#include "common/memstream.h"
#include "sci/sci.h"
#include "sci/engine/file.h"
@@ -32,6 +33,112 @@
namespace Sci {
+#ifdef ENABLE_SCI32
+/**
+ * A MemoryWriteStreamDynamic with additional read functionality.
+ * The read and write functions share a single stream position.
+ */
+class MemoryDynamicRWStream : public Common::MemoryWriteStreamDynamic, public Common::SeekableReadStream {
+protected:
+ bool _eos;
+public:
+ MemoryDynamicRWStream(DisposeAfterUse::Flag disposeMemory = DisposeAfterUse::NO) : MemoryWriteStreamDynamic(disposeMemory), _eos(false) { }
+
+ uint32 read(void *dataPtr, uint32 dataSize);
+
+ bool eos() const { return _eos; }
+ int32 pos() const { return _pos; }
+ int32 size() const { return _size; }
+ void clearErr() { _eos = false; Common::MemoryWriteStreamDynamic::clearErr(); }
+ bool seek(int32 offs, int whence = SEEK_SET) { return Common::MemoryWriteStreamDynamic::seek(offs, whence); }
+
+};
+
+uint32 MemoryDynamicRWStream::read(void *dataPtr, uint32 dataSize)
+{
+ // Read at most as many bytes as are still available...
+ if (dataSize > _size - _pos) {
+ dataSize = _size - _pos;
+ _eos = true;
+ }
+ memcpy(dataPtr, _ptr, dataSize);
+
+ _ptr += dataSize;
+ _pos += dataSize;
+
+ return dataSize;
+}
+
+/**
+ * A MemoryDynamicRWStream intended to re-write a file.
+ * It reads the contents of `inFile` in the constructor, and writes back
+ * the changes to `fileName` in the destructor (and when calling commit() ).
+ */
+class SaveFileRewriteStream : public MemoryDynamicRWStream {
+public:
+ SaveFileRewriteStream(Common::String fileName,
+ Common::SeekableReadStream *inFile,
+ bool truncate, bool compress);
+ virtual ~SaveFileRewriteStream();
+
+ virtual uint32 write(const void *dataPtr, uint32 dataSize) { _changed = true; return MemoryDynamicRWStream::write(dataPtr, dataSize); }
+
+ void commit(); //< Save back to disk
+
+protected:
+ Common::String _fileName;
+ bool _compress;
+ bool _changed;
+};
+
+SaveFileRewriteStream::SaveFileRewriteStream(Common::String fileName,
+ Common::SeekableReadStream *inFile,
+ bool truncate,
+ bool compress)
+: MemoryDynamicRWStream(DisposeAfterUse::YES),
+ _fileName(fileName), _compress(compress)
+{
+ if (!truncate && inFile) {
+ unsigned int s = inFile->size();
+ ensureCapacity(s);
+ inFile->read(_data, s);
+ _changed = false;
+ } else {
+ _changed = true;
+ }
+}
+
+SaveFileRewriteStream::~SaveFileRewriteStream() {
+ commit();
+}
+
+void SaveFileRewriteStream::commit() {
+ // Write contents of buffer back to file
+
+ if (_changed) {
+ Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName, _compress);
+ outFile->write(_data, _size);
+ delete outFile;
+ _changed = false;
+ }
+}
+
+#endif
+
+uint findFreeFileHandle(EngineState *s) {
+ // Find a free file handle
+ uint handle = 1; // Ignore _fileHandles[0]
+ while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen())
+ handle++;
+
+ if (handle == s->_fileHandles.size()) {
+ // Hit size limit => Allocate more space
+ s->_fileHandles.resize(s->_fileHandles.size() + 1);
+ }
+
+ return handle;
+}
+
/*
* Note on how file I/O is implemented: In ScummVM, one can not create/write
* arbitrary data files, simply because many of our target platforms do not
@@ -91,6 +198,27 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
break;
}
+#ifdef ENABLE_SCI32
+ if (mode != _K_FILE_MODE_OPEN_OR_FAIL && (
+ (g_sci->getGameId() == GID_PHANTASMAGORIA && filename == "phantsg.dir") ||
+ (g_sci->getGameId() == GID_PQSWAT && filename == "swat.dat"))) {
+ debugC(kDebugLevelFile, " -> file_open opening %s for rewriting", wrappedName.c_str());
+
+ inFile = saveFileMan->openForLoading(wrappedName);
+ // If no matching savestate exists: fall back to reading from a regular
+ // file
+ if (!inFile)
+ inFile = SearchMan.createReadStreamForMember(englishName);
+
+ SaveFileRewriteStream *stream;
+ stream = new SaveFileRewriteStream(wrappedName, inFile, mode == _K_FILE_MODE_CREATE, isCompressed);
+
+ delete inFile;
+
+ inFile = stream;
+ outFile = stream;
+ } else
+#endif
if (mode == _K_FILE_MODE_OPEN_OR_FAIL) {
// Try to open file, abort if not possible
inFile = saveFileMan->openForLoading(wrappedName);
@@ -126,15 +254,7 @@ reg_t file_open(EngineState *s, const Common::String &filename, int mode, bool u
return SIGNAL_REG;
}
- // Find a free file handle
- uint handle = 1; // Ignore _fileHandles[0]
- while ((handle < s->_fileHandles.size()) && s->_fileHandles[handle].isOpen())
- handle++;
-
- if (handle == s->_fileHandles.size()) {
- // Hit size limit => Allocate more space
- s->_fileHandles.resize(s->_fileHandles.size() + 1);
- }
+ uint handle = findFreeFileHandle(s);
s->_fileHandles[handle]._in = inFile;
s->_fileHandles[handle]._out = outFile;
@@ -252,8 +372,12 @@ FileHandle::~FileHandle() {
}
void FileHandle::close() {
- delete _in;
- delete _out;
+ // NB: It is possible _in and _out are both non-null, but
+ // then they point to the same object.
+ if (_in)
+ delete _in;
+ else
+ delete _out;
_in = 0;
_out = 0;
_name.clear();
@@ -365,119 +489,4 @@ reg_t DirSeeker::nextFile(SegManager *segMan) {
return _outbuffer;
}
-
-#ifdef ENABLE_SCI32
-
-VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName), _changed(false) {
- Common::SeekableReadStream *inFile = g_sci->getSaveFileManager()->openForLoading(fileName);
-
- _bufferSize = inFile->size();
- _buffer = new char[_bufferSize];
- inFile->read(_buffer, _bufferSize);
- _ptr = _buffer;
- delete inFile;
-}
-
-VirtualIndexFile::VirtualIndexFile(uint32 initialSize) : _changed(false) {
- _bufferSize = initialSize;
- _buffer = new char[_bufferSize];
- _ptr = _buffer;
-}
-
-VirtualIndexFile::~VirtualIndexFile() {
- close();
-
- _bufferSize = 0;
- delete[] _buffer;
- _buffer = 0;
-}
-
-uint32 VirtualIndexFile::read(char *buffer, uint32 size) {
- uint32 curPos = _ptr - _buffer;
- uint32 finalSize = MIN<uint32>(size, _bufferSize - curPos);
- char *localPtr = buffer;
-
- for (uint32 i = 0; i < finalSize; i++)
- *localPtr++ = *_ptr++;
-
- return finalSize;
-}
-
-uint32 VirtualIndexFile::write(const char *buffer, uint32 size) {
- _changed = true;
- uint32 curPos = _ptr - _buffer;
-
- // Check if the buffer needs to be resized
- if (curPos + size >= _bufferSize) {
- _bufferSize = curPos + size + 1;
- char *tmp = _buffer;
- _buffer = new char[_bufferSize];
- _ptr = _buffer + curPos;
- memcpy(_buffer, tmp, _bufferSize);
- delete[] tmp;
- }
-
- for (uint32 i = 0; i < size; i++)
- *_ptr++ = *buffer++;
-
- return size;
-}
-
-uint32 VirtualIndexFile::readLine(char *buffer, uint32 size) {
- uint32 startPos = _ptr - _buffer;
- uint32 bytesRead = 0;
- char *localPtr = buffer;
-
- // This is not a full-blown implementation of readLine, but it
- // suffices for Phantasmagoria
- while (startPos + bytesRead < size) {
- bytesRead++;
-
- if (*_ptr == 0 || *_ptr == 0x0A) {
- _ptr++;
- *localPtr = 0;
- return bytesRead;
- } else {
- *localPtr++ = *_ptr++;
- }
- }
-
- return bytesRead;
-}
-
-bool VirtualIndexFile::seek(int32 offset, int whence) {
- uint32 startPos = _ptr - _buffer;
- assert(offset >= 0);
-
- switch (whence) {
- case SEEK_CUR:
- assert(startPos + offset < _bufferSize);
- _ptr += offset;
- break;
- case SEEK_SET:
- assert(offset < (int32)_bufferSize);
- _ptr = _buffer + offset;
- break;
- case SEEK_END:
- assert((int32)_bufferSize - offset >= 0);
- _ptr = _buffer + (_bufferSize - offset);
- break;
- }
-
- return true;
-}
-
-void VirtualIndexFile::close() {
- if (_changed && !_fileName.empty()) {
- Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName);
- outFile->write(_buffer, _bufferSize);
- delete outFile;
- }
-
- // Maintain the buffer, and seek to the beginning of it
- _ptr = _buffer;
-}
-
-#endif
-
} // End of namespace Sci
diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h
index 54627d5228..982d7b7823 100644
--- a/engines/sci/engine/file.h
+++ b/engines/sci/engine/file.h
@@ -43,7 +43,6 @@ enum {
#define VIRTUALFILE_HANDLE_START 32000
#define VIRTUALFILE_HANDLE_SCI32SAVE 32100
-#define PHANTASMAGORIA_SAVEGAME_INDEX "phantsg.dir"
#define VIRTUALFILE_HANDLE_SCIAUDIO 32300
#define VIRTUALFILE_HANDLE_END 32300
@@ -93,50 +92,7 @@ private:
void addAsVirtualFiles(Common::String title, Common::String fileMask);
};
-
-#ifdef ENABLE_SCI32
-
-/**
- * An implementation of a virtual file that supports basic read and write
- * operations simultaneously.
- *
- * This class has been initially implemented for Phantasmagoria, which has its
- * own custom save/load code. The load code keeps checking for the existence
- * of the save index file and keeps closing and reopening it for each save
- * slot. This is notoriously slow and clumsy, and introduces noticeable delays,
- * especially for non-desktop systems. Also, its game scripts request to open
- * the index file for reading and writing with the same parameters
- * (SaveManager::setCurrentSave and SaveManager::getCurrentSave). Moreover,
- * the game scripts reopen the index file for writing in order to update it
- * and seek within it. We do not support seeking in writeable streams, and the
- * fact that our saved games are ZIP files makes this operation even more
- * expensive. Finally, the savegame index file is supposed to be expanded when
- * a new save slot is added.
- * For the aforementioned reasons, this class has been implemented, which offers
- * the basic functionality needed by the game scripts in Phantasmagoria.
- */
-class VirtualIndexFile {
-public:
- VirtualIndexFile(Common::String fileName);
- VirtualIndexFile(uint32 initialSize);
- ~VirtualIndexFile();
-
- uint32 read(char *buffer, uint32 size);
- uint32 readLine(char *buffer, uint32 size);
- uint32 write(const char *buffer, uint32 size);
- bool seek(int32 offset, int whence);
- void close();
-
-private:
- char *_buffer;
- uint32 _bufferSize;
- char *_ptr;
-
- Common::String _fileName;
- bool _changed;
-};
-
-#endif
+uint findFreeFileHandle(EngineState *s);
} // End of namespace Sci
diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp
index 70c8c52bf0..b229490570 100644
--- a/engines/sci/engine/gc.cpp
+++ b/engines/sci/engine/gc.cpp
@@ -24,6 +24,10 @@
#include "common/array.h"
#include "sci/graphics/ports.h"
+#ifdef ENABLE_SCI32
+#include "sci/graphics/controls32.h"
+#endif
+
namespace Sci {
//#define GC_DEBUG_CODE
@@ -150,6 +154,12 @@ AddrSet *findAllActiveReferences(EngineState *s) {
}
}
+#ifdef ENABLE_SCI32
+ // Init: ScrollWindows
+ if (g_sci->_gfxControls32)
+ wm.pushArray(g_sci->_gfxControls32->listObjectReferences());
+#endif
+
debugC(kDebugLevelGC, "[GC] -- Finished explicitly loaded scripts, done with root set");
processWorkList(s->_segMan, wm, heap);
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 0df4701334..2afb8b73d1 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -84,13 +84,19 @@ uint Kernel::getKernelNamesSize() const {
}
const Common::String &Kernel::getKernelName(uint number) const {
- // FIXME: The following check is a temporary workaround for an issue
- // leading to crashes when using the debugger's backtrace command.
- if (number >= _kernelNames.size())
- return _invalid;
+ assert(number < _kernelFuncs.size());
return _kernelNames[number];
}
+Common::String Kernel::getKernelName(uint number, uint subFunction) const {
+ assert(number < _kernelFuncs.size());
+ const KernelFunction &kernelCall = _kernelFuncs[number];
+
+ assert(subFunction < kernelCall.subFunctionCount);
+ return kernelCall.subFunctions[subFunction].name;
+}
+
+
int Kernel::findKernelFuncPos(Common::String kernelFuncName) {
for (uint32 i = 0; i < _kernelNames.size(); i++)
if (_kernelNames[i] == kernelFuncName)
@@ -853,7 +859,7 @@ void Kernel::loadKernelNames(GameFeatures *features) {
_kernelNames[0x26] = "Portrait";
else if (g_sci->getPlatform() == Common::kPlatformMacintosh)
_kernelNames[0x84] = "ShowMovie";
- } else if (g_sci->getGameId() == GID_QFG4 && g_sci->isDemo()) {
+ } else if (g_sci->getGameId() == GID_QFG4DEMO) {
_kernelNames[0x7b] = "RemapColors"; // QFG4 Demo has this SCI2 function instead of StrSplit
}
@@ -879,8 +885,8 @@ void Kernel::loadKernelNames(GameFeatures *features) {
// how kDoSound is called from Sound::play().
// Known games that use this:
// GK2 demo
- // KQ7 1.4
- // PQ4 SWAT demo
+ // KQ7 1.4/1.51
+ // PQ:SWAT demo
// LSL6
// PQ4CD
// QFG4CD
@@ -891,7 +897,7 @@ void Kernel::loadKernelNames(GameFeatures *features) {
_kernelNames = Common::StringArray(sci2_default_knames, kKernelEntriesGk2Demo);
// OnMe is IsOnMe here, but they should be compatible
- _kernelNames[0x23] = "Robot"; // Graph in SCI2
+ _kernelNames[0x23] = g_sci->getGameId() == GID_LSL6HIRES ? "Empty" : "Robot"; // Graph in SCI2
_kernelNames[0x2e] = "Priority"; // DisposeTextBitmap in SCI2
} else {
// Normal SCI2.1 kernel table
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 92916ecc68..5ff4f932be 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -158,6 +158,7 @@ public:
uint getKernelNamesSize() const;
const Common::String &getKernelName(uint number) const;
+ Common::String getKernelName(uint number, uint subFunction) const;
/**
* Determines the selector ID of a selector by its name.
@@ -420,6 +421,35 @@ reg_t kStubNull(EngineState *s, int argc, reg_t *argv);
#ifdef ENABLE_SCI32
// SCI2 Kernel Functions
+reg_t kDoAudio32(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioInit(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioWaitForPlay(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPlay(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioStop(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPause(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioResume(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPosition(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioRate(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioVolume(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioGetCapability(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioBitDepth(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioDistort(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioMixing(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioChannels(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioPreload(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv);
+reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv);
+
+reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv);
+reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv);
+
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
reg_t kArray(EngineState *s, int argc, reg_t *argv);
reg_t kListAt(EngineState *s, int argc, reg_t *argv);
@@ -447,28 +477,61 @@ reg_t kStringTrnExclude(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowPageUp(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowPageDown(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowUpArrow(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowDownArrow(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowHome(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowEnd(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowGo(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowModify(EngineState *s, int argc, reg_t *argv);
+reg_t kScrollWindowHide(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv);
reg_t kMulDiv(EngineState *s, int argc, reg_t *argv);
-reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv);
+
reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv);
+reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv);
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv);
-reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmap(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapDrawBitmap(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapCreateFromView(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapCopyPixels(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapClone(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapGetInfo(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapScale(EngineState *s, int argc, reg_t *argv);
+reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv);
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv);
reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv);
reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv);
+reg_t kMovePlaneItems(EngineState *s, int argc, reg_t *argv);
reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv);
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv);
reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv);
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv);
+reg_t kCelHigh32(EngineState *s, int argc, reg_t *argv);
+reg_t kCelWide32(EngineState *s, int argc, reg_t *argv);
reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv); // kOnMe for SCI2, kIsOnMe for SCI2.1
reg_t kInPolygon(EngineState *s, int argc, reg_t *argv);
@@ -484,8 +547,17 @@ reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv);
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv);
-reg_t kPalCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv);
+reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv);
reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv);
+
+reg_t kPalCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv);
+reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv);
+
reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv);
reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv);
reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv);
@@ -499,6 +571,8 @@ reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv);
// SCI2.1 Kernel Functions
reg_t kMorphOn(EngineState *s, int argc, reg_t *argv);
reg_t kText(EngineState *s, int argc, reg_t *argv);
+reg_t kTextSize32(EngineState *s, int argc, reg_t *argv);
+reg_t kTextWidth(EngineState *s, int argc, reg_t *argv);
reg_t kSave(EngineState *s, int argc, reg_t *argv);
reg_t kAutoSave(EngineState *s, int argc, reg_t *argv);
reg_t kList(EngineState *s, int argc, reg_t *argv);
@@ -511,14 +585,15 @@ reg_t kMoveToFront(EngineState *s, int argc, reg_t *argv);
reg_t kMoveToEnd(EngineState *s, int argc, reg_t *argv);
reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv);
reg_t kWinHelp(EngineState *s, int argc, reg_t *argv);
+reg_t kMessageBox(EngineState *s, int argc, reg_t *argv);
reg_t kGetConfig(EngineState *s, int argc, reg_t *argv);
reg_t kGetSierraProfileInt(EngineState *s, int argc, reg_t *argv);
reg_t kCelInfo(EngineState *s, int argc, reg_t *argv);
reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv);
reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv);
+reg_t kSetFontHeight(EngineState *s, int argc, reg_t *argv);
reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv);
reg_t kFont(EngineState *s, int argc, reg_t *argv);
-reg_t kBitmap(EngineState *s, int argc, reg_t *argv);
reg_t kAddLine(EngineState *s, int argc, reg_t *argv);
reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv);
reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv);
@@ -532,7 +607,6 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundInit(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundPlay(EngineState *s, int argc, reg_t *argv);
-reg_t kDoSoundRestore(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundDispose(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundMute(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundStop(EngineState *s, int argc, reg_t *argv);
@@ -547,7 +621,6 @@ reg_t kDoSoundUpdateCues(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSendMidi(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundGlobalReverb(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSetHold(EngineState *s, int argc, reg_t *argv);
-reg_t kDoSoundDummy(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundGetAudioCapability(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSuspend(EngineState *s, int argc, reg_t *argv);
reg_t kDoSoundSetVolume(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index fbd0b13c88..8a1176eed8 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -60,15 +60,19 @@ struct SciKernelMapSubEntry {
#define SCI_SUBOPENTRY_TERMINATOR { SCI_VERSION_NONE, SCI_VERSION_NONE, 0, NULL, NULL, NULL, NULL }
-#define SIG_SCIALL SCI_VERSION_NONE, SCI_VERSION_NONE
-#define SIG_SCI0 SCI_VERSION_NONE, SCI_VERSION_01
-#define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE
-#define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1
-#define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE
-#define SIG_SCI21EARLY_ONLY SCI_VERSION_2_1_EARLY, SCI_VERSION_2_1_EARLY
-#define SIG_SINCE_SCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3
-#define SIG_UNTIL_SCI21MID SCI_VERSION_2, SCI_VERSION_2_1_MIDDLE
-#define SIG_SINCE_SCI21LATE SCI_VERSION_2_1_LATE, SCI_VERSION_3
+#define SIG_SCIALL SCI_VERSION_NONE, SCI_VERSION_NONE
+#define SIG_SCI0 SCI_VERSION_NONE, SCI_VERSION_01
+#define SIG_SCI1 SCI_VERSION_1_EGA_ONLY, SCI_VERSION_1_LATE
+#define SIG_SCI11 SCI_VERSION_1_1, SCI_VERSION_1_1
+#define SIG_SINCE_SCI11 SCI_VERSION_1_1, SCI_VERSION_NONE
+#define SIG_SCI2 SCI_VERSION_2, SCI_VERSION_2
+#define SIG_SCI21EARLY SCI_VERSION_2_1_EARLY, SCI_VERSION_2_1_EARLY
+#define SIG_UNTIL_SCI21EARLY SCI_VERSION_2, SCI_VERSION_2_1_EARLY
+#define SIG_UNTIL_SCI21MID SCI_VERSION_2, SCI_VERSION_2_1_MIDDLE
+#define SIG_SINCE_SCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3
+#define SIG_SINCE_SCI21MID SCI_VERSION_2_1_MIDDLE, SCI_VERSION_3
+#define SIG_SINCE_SCI21LATE SCI_VERSION_2_1_LATE, SCI_VERSION_3
+#define SIG_SCI3 SCI_VERSION_3, SCI_VERSION_3
#define SIG_SCI16 SCI_VERSION_NONE, SCI_VERSION_1_1
#define SIG_SCI32 SCI_VERSION_2, SCI_VERSION_NONE
@@ -98,7 +102,7 @@ struct SciKernelMapSubEntry {
static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 0, MAP_CALL(DoSoundInit), "o", NULL },
{ SIG_SOUNDSCI0, 1, MAP_CALL(DoSoundPlay), "o", NULL },
- { SIG_SOUNDSCI0, 2, MAP_CALL(DoSoundRestore), "(o)", NULL },
+ { SIG_SOUNDSCI0, 2, MAP_EMPTY(DoSoundRestore), "(o)", NULL },
{ SIG_SOUNDSCI0, 3, MAP_CALL(DoSoundDispose), "o", NULL },
{ SIG_SOUNDSCI0, 4, MAP_CALL(DoSoundMute), "(i)", NULL },
{ SIG_SOUNDSCI0, 5, MAP_CALL(DoSoundStop), "o", NULL },
@@ -111,7 +115,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI0, 12, MAP_CALL(DoSoundStopAll), "", NULL },
{ SIG_SOUNDSCI1EARLY, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1EARLY, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
+ { SIG_SOUNDSCI1EARLY, 2, MAP_EMPTY(DoSoundRestore), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 4, MAP_CALL(DoSoundUpdate), NULL, NULL },
{ SIG_SOUNDSCI1EARLY, 5, MAP_CALL(DoSoundInit), NULL, NULL },
@@ -124,11 +128,11 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1EARLY, 12, MAP_CALL(DoSoundSendMidi), "oiii", NULL },
{ SIG_SOUNDSCI1EARLY, 13, MAP_CALL(DoSoundGlobalReverb), "(i)", NULL },
{ SIG_SOUNDSCI1EARLY, 14, MAP_CALL(DoSoundSetHold), "oi", NULL },
- { SIG_SOUNDSCI1EARLY, 15, MAP_CALL(DoSoundDummy), "", NULL },
+ { SIG_SOUNDSCI1EARLY, 15, MAP_EMPTY(DoSoundDummy), "", NULL },
// ^^ Longbow demo
{ SIG_SOUNDSCI1LATE, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 2, MAP_CALL(DoSoundRestore), "", NULL },
+ { SIG_SOUNDSCI1LATE, 2, MAP_EMPTY(DoSoundRestore), "", NULL },
{ SIG_SOUNDSCI1LATE, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
{ SIG_SOUNDSCI1LATE, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
@@ -139,7 +143,7 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1LATE, 10, MAP_CALL(DoSoundPause), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 11, MAP_CALL(DoSoundFade), "oiiii(i)", kDoSoundFade_workarounds },
{ SIG_SOUNDSCI1LATE, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
- { SIG_SOUNDSCI1LATE, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI1LATE, 13, MAP_EMPTY(DoSoundDummy), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
{ SIG_SOUNDSCI1LATE, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
{ SIG_SOUNDSCI1LATE, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
@@ -148,36 +152,97 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundGlobalReverb), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
#ifdef ENABLE_SCI32
- { SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), NULL, NULL },
- { SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), NULL, NULL },
- { SIG_SOUNDSCI21, 2, MAP_CALL(DoSoundRestore), NULL, NULL },
- { SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), NULL, NULL },
- { SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), NULL, NULL },
- { SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), NULL, NULL },
- { SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), NULL, NULL },
- { SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), NULL, NULL },
- { SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o(i)", NULL },
+ { SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
+ { SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), "(i)", NULL },
+ { SIG_SOUNDSCI21, 2, MAP_EMPTY(DoSoundRestore), NULL, NULL },
+ { SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), "", NULL },
+ { SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
+ { SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
+ { SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), "o", NULL },
+ { SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), "o", NULL },
+ { SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o", kDoSoundPlay_workarounds },
// ^^ TODO: if this is really the only change between SCI1LATE AND SCI21, we could rename the
// SIG_SOUNDSCI1LATE #define to SIG_SINCE_SOUNDSCI1LATE and make it being SCI1LATE+. Although
// I guess there are many more changes somewhere
// TODO: Quest for Glory 4 (SCI2.1) uses the old scheme, we need to detect it accordingly
// signature for SCI21 should be "o"
- { SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), NULL, NULL },
- { SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), NULL, NULL },
- { SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), NULL, kDoSoundFade_workarounds },
- { SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), NULL, NULL },
- { SIG_SOUNDSCI21, 13, MAP_CALL(DoSoundDummy), NULL, NULL },
- { SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), NULL, NULL },
- { SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), NULL, NULL },
- { SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), NULL, NULL },
- { SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), NULL, NULL },
- { SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), NULL, NULL },
- { SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundGlobalReverb), NULL, NULL },
- { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
+ { SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), "o", NULL },
+ { SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), "[o0]i", NULL },
+ { SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
+ { SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), "oi", NULL },
+ { SIG_SOUNDSCI21, 13, MAP_EMPTY(DoSoundDummy), NULL, NULL },
+ { SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
+ { SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
+ { SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
+ { SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), "o", NULL },
+ { SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), "oiiii", NULL },
+ { SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundGlobalReverb), "(i)", NULL },
+ { SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), "o", NULL },
#endif
SCI_SUBOPENTRY_TERMINATOR
};
+#ifdef ENABLE_SCI32
+// NOTE: In SSCI, some 'unused' kDoAudio subops are actually
+// called indirectly by kDoSound:
+//
+// kDoSoundGetAudioCapability -> kDoAudioGetCapability
+// kDoSoundPlay -> kDoAudioPlay, kDoAudioStop
+// kDoSoundPause -> kDoAudioPause, kDoAudioResume
+// kDoSoundFade -> kDoAudioFade
+// kDoSoundSetVolume -> kDoAudioVolume
+// kDoSoundSetLoop -> kDoAudioSetLoop
+// kDoSoundUpdateCues -> kDoAudioPosition
+//
+// In ScummVM, logic inside these kernel functions has been
+// moved to methods of Audio32, and direct calls to Audio32
+// are made from kDoSound instead.
+//
+// Some kDoAudio methods are esoteric and appear to be used
+// only by one or two games:
+//
+// kDoAudioMixing: Phantasmagoria (other games call this
+// function, but only to disable the feature)
+// kDoAudioHasSignal: SQ6 TalkRandCycle
+// kDoAudioPan: Rama RegionSFX::pan method
+//
+// Finally, there is a split in SCI2.1mid audio code.
+// QFG4CD & SQ6 do not have opcodes 18 and 19, but they
+// exist in GK2, KQ7 2.00b, Phantasmagoria 1, PQ:SWAT, and
+// Torin. (It is unknown if they exist in MUMG Deluxe or
+// Shivers 1; they are not used in either of these games.)
+
+// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kDoAudio_subops[] = {
+ { SIG_SCI32, 0, MAP_CALL(DoAudioInit), "", NULL },
+ // SCI2 includes a Sync script that would call
+ // kDoAudioWaitForPlay, but SSCI has no opcode 1 until
+ // SCI2.1early
+ { SIG_SINCE_SCI21, 1, MAP_CALL(DoAudioWaitForPlay), "(i)(i)(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(DoAudioPlay), "(i)(i)(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(DoAudioStop), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(DoAudioPause), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 5, MAP_CALL(DoAudioResume), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 6, MAP_CALL(DoAudioPosition), "(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 7, MAP_CALL(DoAudioRate), "(i)", NULL },
+ { SIG_SCI32, 8, MAP_CALL(DoAudioVolume), "(i)(i)(i)(i)(i)(i)", NULL },
+ { SIG_SCI32, 9, MAP_CALL(DoAudioGetCapability), "", NULL },
+ { SIG_SCI32, 10, MAP_CALL(DoAudioBitDepth), "(i)", NULL },
+ { SIG_SCI32, 11, MAP_DUMMY(DoAudioDistort), "(i)", NULL },
+ { SIG_SCI32, 12, MAP_CALL(DoAudioMixing), "(i)", NULL },
+ { SIG_SCI32, 13, MAP_CALL(DoAudioChannels), "(i)", NULL },
+ { SIG_SCI32, 14, MAP_CALL(DoAudioPreload), "(i)", NULL },
+ { SIG_SINCE_SCI21MID, 15, MAP_CALL(DoAudioFade), "(iiii)(i)(i)", NULL },
+ { SIG_SINCE_SCI21MID, 16, MAP_DUMMY(DoAudioFade36), "iiiii(iii)(i)", NULL },
+ { SIG_SINCE_SCI21MID, 17, MAP_CALL(DoAudioHasSignal), "", NULL },
+ { SIG_SINCE_SCI21MID, 18, MAP_EMPTY(DoAudioCritical), "", NULL },
+ { SIG_SINCE_SCI21MID, 19, MAP_CALL(DoAudioSetLoop), "iii(o)", NULL },
+ { SIG_SCI3, 20, MAP_DUMMY(DoAudioPan), "", NULL },
+ { SIG_SCI3, 21, MAP_DUMMY(DoAudioPanOff), "", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+#endif
+
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kGraph_subops[] = {
{ SIG_SCI32, 1, MAP_CALL(StubNull), "", NULL }, // called by gk1 sci32 right at the start
@@ -211,7 +276,7 @@ static const SciKernelMapSubEntry kPalVary_subops[] = {
{ SIG_SCI16, 6, MAP_CALL(PalVaryPauseResume), "i", NULL },
#ifdef ENABLE_SCI32
{ SIG_SCI32, 0, MAP_CALL(PalVarySetVary), "i(i)(i)(ii)", NULL },
- { SIG_SCI32, 1, MAP_CALL(PalVarySetPercent), "(i)(i)", NULL },
+ { SIG_SCI32, 1, MAP_CALL(PalVarySetPercent), "(i)(i)", kPalVarySetPercent_workarounds },
{ SIG_SCI32, 2, MAP_CALL(PalVaryGetPercent), "", NULL },
{ SIG_SCI32, 3, MAP_CALL(PalVaryOff), "", NULL },
{ SIG_SCI32, 4, MAP_CALL(PalVaryMergeTarget), "i", NULL },
@@ -226,12 +291,13 @@ static const SciKernelMapSubEntry kPalVary_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kPalette_subops[] = {
- { SIG_SCIALL, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
+ { SIG_SCI16, 1, MAP_CALL(PaletteSetFromResource), "i(i)", NULL },
{ SIG_SCI16, 2, MAP_CALL(PaletteSetFlag), "iii", NULL },
{ SIG_SCI16, 3, MAP_CALL(PaletteUnsetFlag), "iii", kPaletteUnsetFlag_workarounds },
#ifdef ENABLE_SCI32
+ { SIG_SCI32, 1, MAP_CALL(PaletteSetFromResource32), "i(i)", NULL },
{ SIG_SCI32, 2, MAP_CALL(PaletteSetFade), "iii", NULL },
- { SIG_SCI32, 3, MAP_CALL(PaletteFindColor), "iii", NULL },
+ { SIG_SCI32, 3, MAP_CALL(PaletteFindColor32), "iii", NULL },
#endif
{ SIG_SCI16, 4, MAP_CALL(PaletteSetIntensity), "iii(i)", NULL },
{ SIG_SCI16, 5, MAP_CALL(PaletteFindColor), "iii", NULL },
@@ -270,6 +336,16 @@ static const SciKernelMapSubEntry kFileIO_subops[] = {
#ifdef ENABLE_SCI32
// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kPalCycle_subops[] = {
+ { SIG_SCI32, 0, MAP_CALL(PalCycleSetCycle), "iii(i)", NULL },
+ { SIG_SCI32, 1, MAP_CALL(PalCycleDoCycle), "i(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(PalCyclePause), "(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(PalCycleOn), "(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(PalCycleOff), "(i)", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kSave_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(SaveGame), "[r0]i[r0](r0)", NULL },
{ SIG_SCI32, 1, MAP_CALL(RestoreGame), "[r0]i[r0]", NULL },
@@ -284,6 +360,42 @@ static const SciKernelMapSubEntry kSave_subops[] = {
};
// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kFont_subops[] = {
+ { SIG_SINCE_SCI21MID, 0, MAP_CALL(SetFontHeight), "i", NULL },
+ { SIG_SINCE_SCI21MID, 1, MAP_CALL(SetFontRes), "ii", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kText_subops[] = {
+ { SIG_SINCE_SCI21MID, 0, MAP_CALL(TextSize32), "r[r0]i(i)(i)", NULL },
+ { SIG_SINCE_SCI21MID, 1, MAP_CALL(TextWidth), "ri", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kBitmap_subops[] = {
+ { SIG_SINCE_SCI21, 0, MAP_CALL(BitmapCreate), "iiii(i)(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 1, MAP_CALL(BitmapDestroy), "r", NULL },
+ { SIG_SINCE_SCI21, 2, MAP_CALL(BitmapDrawLine), "riiiii(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 3, MAP_CALL(BitmapDrawView), "riii(i)(i)(0)(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 4, MAP_CALL(BitmapDrawText), "rriiiiiiiiiii", NULL },
+ { SIG_SINCE_SCI21, 5, MAP_CALL(BitmapDrawColor), "riiiii", NULL },
+ { SIG_SINCE_SCI21, 6, MAP_CALL(BitmapDrawBitmap), "rr(i)(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 7, MAP_CALL(BitmapInvert), "riiiiii", NULL },
+ { SIG_SINCE_SCI21MID, 8, MAP_CALL(BitmapSetDisplace), "rii", NULL },
+ { SIG_SINCE_SCI21MID, 9, MAP_CALL(BitmapCreateFromView), "iii(i)(i)(i)([r0])", NULL },
+ { SIG_SINCE_SCI21MID, 10, MAP_CALL(BitmapCopyPixels), "rr", NULL },
+ { SIG_SINCE_SCI21MID, 11, MAP_CALL(BitmapClone), "r", NULL },
+ { SIG_SINCE_SCI21LATE, 12, MAP_CALL(BitmapGetInfo), "r(i)(i)", NULL },
+ { SIG_SINCE_SCI21LATE, 13, MAP_CALL(BitmapScale), "r...ii", NULL },
+ { SIG_SCI3, 14, MAP_CALL(BitmapCreateFromUnknown), "......", NULL },
+ { SIG_SCI3, 15, MAP_EMPTY(Bitmap), "(.*)", NULL },
+ { SIG_SCI3, 16, MAP_EMPTY(Bitmap), "(.*)", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kList_subops[] = {
{ SIG_SINCE_SCI21, 0, MAP_CALL(NewList), "", NULL },
{ SIG_SINCE_SCI21, 1, MAP_CALL(DisposeList), "l", NULL },
@@ -311,6 +423,33 @@ static const SciKernelMapSubEntry kList_subops[] = {
SCI_SUBOPENTRY_TERMINATOR
};
+// There are a lot of subops to PlayVMD, but only a few of them are ever
+// actually used by games
+// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kPlayVMD_subops[] = {
+ { SIG_SINCE_SCI21, 0, MAP_CALL(PlayVMDOpen), "r(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 1, MAP_CALL(PlayVMDInit), "ii(i)(i)(ii)", NULL },
+ { SIG_SINCE_SCI21, 6, MAP_CALL(PlayVMDClose), "", NULL },
+ { SIG_SINCE_SCI21, 14, MAP_CALL(PlayVMDPlayUntilEvent), "i(i)(i)", NULL },
+ { SIG_SINCE_SCI21, 16, MAP_CALL(PlayVMDShowCursor), "i", NULL },
+ { SIG_SINCE_SCI21, 17, MAP_DUMMY(PlayVMDStartBlob), "", NULL },
+ { SIG_SINCE_SCI21, 18, MAP_DUMMY(PlayVMDStopBlobs), "", NULL },
+ { SIG_SINCE_SCI21, 21, MAP_CALL(PlayVMDSetBlackoutArea), "iiii", NULL },
+ { SIG_SINCE_SCI21, 23, MAP_CALL(PlayVMDRestrictPalette), "ii", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
+// version, subId, function-mapping, signature, workarounds
+static const SciKernelMapSubEntry kRemapColors_subops[] = {
+ { SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL },
+ { SIG_SCI32, 1, MAP_CALL(RemapColorsByRange), "iiii(i)", NULL },
+ { SIG_SCI32, 2, MAP_CALL(RemapColorsByPercent), "ii(i)", NULL },
+ { SIG_SCI32, 3, MAP_CALL(RemapColorsToGray), "ii(i)", NULL },
+ { SIG_SCI32, 4, MAP_CALL(RemapColorsToPercentGray), "iii(i)", NULL },
+ { SIG_SCI32, 5, MAP_CALL(RemapColorsBlockRange), "ii", NULL },
+ SCI_SUBOPENTRY_TERMINATOR
+};
+
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kString_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(StringNew), "i(i)", NULL },
@@ -356,25 +495,30 @@ static const SciKernelMapSubEntry kString_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kScrollWindow_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(ScrollWindowCreate), "oi", NULL },
- { SIG_SCI32, 1, MAP_CALL(ScrollWindowAdd), "o.ii.(.)", NULL },
- { SIG_SCI32, 2, MAP_DUMMY(ScrollWindowClear), "o", NULL },
- { SIG_SCI32, 3, MAP_DUMMY(ScrollWindowPageUp), "o", NULL },
- { SIG_SCI32, 4, MAP_DUMMY(ScrollWindowPageDown), "o", NULL },
- { SIG_SCI32, 5, MAP_DUMMY(ScrollWindowUpArrow), "o", NULL },
- { SIG_SCI32, 6, MAP_DUMMY(ScrollWindowDownArrow), "o", NULL },
- { SIG_SCI32, 7, MAP_DUMMY(ScrollWindowHome), "o", NULL },
- { SIG_SCI32, 8, MAP_DUMMY(ScrollWindowEnd), "o", NULL },
- { SIG_SCI32, 9, MAP_DUMMY(ScrollWindowResize), "o.", NULL },
- { SIG_SCI32, 10, MAP_CALL(ScrollWindowWhere), "oi", NULL },
- { SIG_SCI32, 11, MAP_DUMMY(ScrollWindowGo), "o..", NULL },
- { SIG_SCI32, 12, MAP_DUMMY(ScrollWindowInsert), "o.....", NULL },
- { SIG_SCI32, 13, MAP_DUMMY(ScrollWindowDelete), "o.", NULL },
- { SIG_SCI32, 14, MAP_DUMMY(ScrollWindowModify), "o.....(.)", NULL },
- { SIG_SCI32, 15, MAP_DUMMY(ScrollWindowHide), "o", NULL },
- { SIG_SCI32, 16, MAP_CALL(ScrollWindowShow), "o", NULL },
- { SIG_SCI32, 17, MAP_CALL(ScrollWindowDestroy), "o", NULL },
- { SIG_SCI32, 18, MAP_DUMMY(ScrollWindowText), "o", NULL },
- { SIG_SCI32, 19, MAP_DUMMY(ScrollWindowReconstruct), "o.", NULL },
+ { SIG_SCI32, 1, MAP_CALL(ScrollWindowAdd), "iriii(i)", kScrollWindowAdd_workarounds },
+ { SIG_SCI32, 2, MAP_DUMMY(ScrollWindowClear), "i", NULL },
+ { SIG_SCI32, 3, MAP_CALL(ScrollWindowPageUp), "i", NULL },
+ { SIG_SCI32, 4, MAP_CALL(ScrollWindowPageDown), "i", NULL },
+ { SIG_SCI32, 5, MAP_CALL(ScrollWindowUpArrow), "i", NULL },
+ { SIG_SCI32, 6, MAP_CALL(ScrollWindowDownArrow), "i", NULL },
+ { SIG_SCI32, 7, MAP_CALL(ScrollWindowHome), "i", NULL },
+ { SIG_SCI32, 8, MAP_CALL(ScrollWindowEnd), "i", NULL },
+ { SIG_SCI32, 9, MAP_DUMMY(ScrollWindowResize), "i.", NULL },
+ { SIG_SCI32, 10, MAP_CALL(ScrollWindowWhere), "ii", NULL },
+ { SIG_SCI32, 11, MAP_CALL(ScrollWindowGo), "i..", NULL },
+ { SIG_SCI32, 12, MAP_DUMMY(ScrollWindowInsert), "i.....", NULL },
+ { SIG_SCI32, 13, MAP_DUMMY(ScrollWindowDelete), "i.", NULL },
+ { SIG_SCI32, 14, MAP_CALL(ScrollWindowModify), "iiriii(i)", NULL },
+ { SIG_SCI32, 15, MAP_CALL(ScrollWindowHide), "i", NULL },
+ { SIG_SCI32, 16, MAP_CALL(ScrollWindowShow), "i", NULL },
+ { SIG_SCI32, 17, MAP_CALL(ScrollWindowDestroy), "i", NULL },
+ // LSL6hires uses kScrollWindowText and kScrollWindowReconstruct to try to save
+ // and restore the content of the game's subtitle window, but this feature did not
+ // use the normal save/load functionality of the engine and was actually broken
+ // (all text formatting was missing on restore). Since there is no real reason to
+ // save the subtitle scrollback anyway, we just ignore calls to these two functions.
+ { SIG_SCI32, 18, MAP_EMPTY(ScrollWindowText), "i", NULL },
+ { SIG_SCI32, 19, MAP_EMPTY(ScrollWindowReconstruct), "i.", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@@ -406,12 +550,16 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(AvoidPath), SIG_EVERYWHERE, "ii(.*)", NULL, NULL },
{ MAP_CALL(BaseSetter), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(CanBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL },
+ { MAP_CALL(CantBeHere), SIG_SCI16, SIGFOR_ALL, "o(l)", NULL, NULL },
#ifdef ENABLE_SCI32
- { "CantBeHere", kCantBeHere32, SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL },
+ { MAP_CALL(CantBeHere), SIG_SCI32, SIGFOR_ALL, "ol", NULL, NULL },
+#endif
+ { MAP_CALL(CelHigh), SIG_SCI16, SIGFOR_ALL, "ii(i)", NULL, kCelHigh_workarounds },
+ { MAP_CALL(CelWide), SIG_SCI16, SIGFOR_ALL, "ii(i)", NULL, kCelWide_workarounds },
+#ifdef ENABLE_SCI32
+ { "CelHigh", kCelHigh32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, NULL },
+ { "CelWide", kCelWide32, SIG_SCI32, SIGFOR_ALL, "iii", NULL, kCelWide_workarounds },
#endif
- { MAP_CALL(CantBeHere), SIG_EVERYWHERE, "o(l)", NULL, NULL },
- { MAP_CALL(CelHigh), SIG_EVERYWHERE, "ii(i)", NULL, kCelHigh_workarounds },
- { MAP_CALL(CelWide), SIG_EVERYWHERE, "ii(i)", NULL, kCelWide_workarounds },
{ MAP_CALL(CheckFreeSpace), SIG_SCI32, SIGFOR_ALL, "r.*", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_EVERYWHERE, "r", NULL, NULL },
@@ -429,7 +577,10 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(DisposeList), SIG_EVERYWHERE, "l", NULL, NULL },
{ MAP_CALL(DisposeScript), SIG_EVERYWHERE, "i(i*)", NULL, kDisposeScript_workarounds },
{ MAP_CALL(DisposeWindow), SIG_EVERYWHERE, "i(i)", NULL, NULL },
- { MAP_CALL(DoAudio), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop
+ { MAP_CALL(DoAudio), SCI_VERSION_NONE, SCI_VERSION_2, SIGFOR_ALL, "i(.*)", NULL, NULL }, // subop
+#ifdef ENABLE_SCI32
+ { "DoAudio", kDoAudio32, SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kDoAudio_subops, NULL },
+#endif
{ MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL },
{ MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL },
@@ -512,7 +663,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(ReadNumber), SIG_EVERYWHERE, "r", NULL, kReadNumber_workarounds },
{ MAP_CALL(RemapColors), SIG_SCI11, SIGFOR_ALL, "i(i)(i)(i)(i)", NULL, NULL },
#ifdef ENABLE_SCI32
- { "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", NULL, NULL },
+ { "RemapColors", kRemapColors32, SIG_SCI32, SIGFOR_ALL, "i(i)(i)(i)(i)(i)", kRemapColors_subops, NULL },
#endif
{ MAP_CALL(ResCheck), SIG_EVERYWHERE, "ii(iiii)", NULL, NULL },
{ MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
@@ -528,7 +679,10 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(SetDebug), SIG_EVERYWHERE, "(i*)", NULL, NULL },
{ MAP_CALL(SetJump), SIG_EVERYWHERE, "oiii", NULL, NULL },
{ MAP_CALL(SetMenu), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
- { MAP_CALL(SetNowSeen), SIG_EVERYWHERE, "o(i)", NULL, NULL },
+ { MAP_CALL(SetNowSeen), SIG_SCI16, SIGFOR_ALL, "o(i)", NULL, NULL },
+#ifdef ENABLE_SCI32
+ { MAP_CALL(SetNowSeen), SIG_SCI32, SIGFOR_ALL, "o", NULL, NULL },
+#endif
{ MAP_CALL(SetPort), SIG_EVERYWHERE, "i(iiiii)(i)", NULL, kSetPort_workarounds },
{ MAP_CALL(SetQuitStr), SIG_EVERYWHERE, "r", NULL, NULL },
{ MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL },
@@ -546,10 +700,10 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(StrEnd), SIG_EVERYWHERE, "r", NULL, NULL },
{ MAP_CALL(StrLen), SIG_EVERYWHERE, "[r0]", NULL, kStrLen_workarounds },
{ MAP_CALL(StrSplit), SIG_EVERYWHERE, "rr[r0]", NULL, NULL },
- { MAP_CALL(TextColors), SIG_EVERYWHERE, "(i*)", NULL, NULL },
- { MAP_CALL(TextFonts), SIG_EVERYWHERE, "(i*)", NULL, NULL },
- { MAP_CALL(TextSize), SIG_SCIALL, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL },
- { MAP_CALL(TextSize), SIG_EVERYWHERE, "r[r0]i(i)(r0)", NULL, NULL },
+ { MAP_CALL(TextColors), SIG_SCI16, SIGFOR_ALL, "(i*)", NULL, NULL },
+ { MAP_CALL(TextFonts), SIG_SCI16, SIGFOR_ALL, "(i*)", NULL, NULL },
+ { MAP_CALL(TextSize), SIG_SCI16, SIGFOR_MAC, "r[r0]i(i)(r0)(i)", NULL, NULL },
+ { MAP_CALL(TextSize), SIG_SCI16, SIGFOR_ALL, "r[r0]i(i)(r0)", NULL, NULL },
{ MAP_CALL(TimesCos), SIG_EVERYWHERE, "ii", NULL, NULL },
{ "CosMult", kTimesCos, SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(TimesCot), SIG_EVERYWHERE, "ii", NULL, NULL },
@@ -581,13 +735,17 @@ static SciKernelMapEntry s_kernelMap[] = {
#ifdef ENABLE_SCI32
// SCI2 Kernel Functions
// TODO: whoever knows his way through those calls, fix the signatures.
+ { "TextSize", kTextSize32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "r[r0]i(i)", NULL, NULL },
+ { MAP_DUMMY(TextColors), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(.*)", NULL, NULL },
+ { MAP_DUMMY(TextFonts), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(.*)", NULL, NULL },
+
{ MAP_CALL(AddPlane), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(AddScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(Array), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
{ MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
- { MAP_CALL(DisposeTextBitmap), SIG_EVERYWHERE, "r", NULL, NULL },
+ { "DisposeTextBitmap", kBitmapDestroy, SIG_SCI2, SIGFOR_ALL, "r", NULL, NULL },
{ MAP_CALL(FrameOut), SIG_EVERYWHERE, "(i)", NULL, NULL },
{ MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL },
{ MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL },
@@ -597,6 +755,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(ListEachElementDo), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
{ MAP_CALL(ListFirstTrue), SIG_EVERYWHERE, "li(.*)", NULL, NULL },
{ MAP_CALL(ListIndexOf), SIG_EVERYWHERE, "l[o0]", NULL, NULL },
+ // kMessageBox is used only by KQ7 1.51
+ { MAP_CALL(MessageBox), SIG_SCI32, SIGFOR_ALL, "rri", NULL, NULL },
{ "OnMe", kIsOnMe, SIG_EVERYWHERE, "iioi", NULL, NULL },
// Purge is used by the memory manager in SSCI to ensure that X number of bytes (the so called "unmovable
// memory") are available when the current room changes. This is similar to the SCI0-SCI1.1 FlushResources
@@ -613,7 +773,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL },
{ MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL },
{ MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiiii(i)", NULL, NULL },
- { MAP_CALL(PalCycle), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
+ { MAP_CALL(PalCycle), SIG_EVERYWHERE, "(.*)", kPalCycle_subops, NULL },
// SCI2 Empty functions
@@ -649,9 +809,9 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_DUMMY(MarkMemory), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_DUMMY(GetHighItemPri), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_DUMMY(ShowStylePercent), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(InvertRect), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_DUMMY(InvertRect), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(.*)", NULL, NULL },
{ MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(TextWidth), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri", NULL, NULL },
{ MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL },
// SCI2.1 Kernel Functions
@@ -659,24 +819,27 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
{ MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
{ MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
- { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", kPlayVMD_subops, NULL },
{ MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL },
- { MAP_CALL(Text), SIG_EVERYWHERE, "(.*)", NULL, NULL },
+ { MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL },
{ MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii", NULL, NULL },
{ MAP_CALL(GetWindowsOption), SIG_EVERYWHERE, "i", NULL, NULL },
{ MAP_CALL(WinHelp), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(GetConfig), SIG_EVERYWHERE, "ro", NULL, NULL },
{ MAP_CALL(GetSierraProfileInt), SIG_EVERYWHERE, "rri", NULL, NULL },
- { MAP_CALL(CelInfo), SIG_EVERYWHERE, "iiiiii", NULL, NULL },
- { MAP_CALL(SetLanguage), SIG_EVERYWHERE, "r", NULL, NULL },
+ { MAP_CALL(CelInfo), SIG_SINCE_SCI21MID, SIGFOR_ALL, "iiiiii", NULL, NULL },
+ { MAP_CALL(SetLanguage), SIG_SINCE_SCI21MID, SIGFOR_ALL, "r", NULL, NULL },
{ MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "i(.*)", kScrollWindow_subops, NULL },
- { MAP_CALL(SetFontRes), SIG_SCI21EARLY_ONLY, SIGFOR_ALL, "ii", NULL, NULL },
- { MAP_CALL(Font), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
- { MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", NULL, NULL },
- { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiiiiiiii", NULL, NULL },
- { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "[r0]oiiiiiiiii", NULL, NULL },
- { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "[r0]o", NULL, NULL },
+ { MAP_CALL(SetFontRes), SIG_SCI21EARLY, SIGFOR_ALL, "ii", NULL, NULL },
+ { MAP_CALL(Font), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kFont_subops, NULL },
+ { MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", kBitmap_subops, NULL },
+ { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiii(iiiii)", NULL, NULL },
+ // The first argument is a ScreenItem instance ID that is created by the
+ // engine, not the VM; as a result, in ScummVM, this argument looks like
+ // an integer and not an object, although it is an object reference.
+ { MAP_CALL(UpdateLine), SIG_EVERYWHERE, "ioiiii(iiiii)", NULL, NULL },
+ { MAP_CALL(DeleteLine), SIG_EVERYWHERE, "io", NULL, NULL },
// SCI2.1 Empty Functions
@@ -725,9 +888,9 @@ static SciKernelMapEntry s_kernelMap[] = {
// <lskovlun> The idea, if I understand correctly, is that the engine generates events
// of a special HotRect type continuously when the mouse is on that rectangle
- // MovePlaneItems - used by SQ6 to scroll through the inventory via the up/down buttons
- // SetPalStyleRange - 2 integer parameters, start and end. All styles from start-end
- // (inclusive) are set to 0
+ // Used by SQ6 to scroll through the inventory via the up/down buttons
+ { MAP_CALL(MovePlaneItems), SIG_SINCE_SCI21, SIGFOR_ALL, "oii(i)", NULL, NULL },
+
{ MAP_CALL(SetPalStyleRange), SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(MorphOn), SIG_EVERYWHERE, "", NULL, NULL },
@@ -1030,7 +1193,6 @@ static const char *const sci2_default_knames[] = {
/*0x89*/ "TextWidth", // for debugging(?), only in SCI2, not used in any SCI2 game
/*0x8a*/ "PointSize", // for debugging(?), only in SCI2, not used in any SCI2 game
- // GK2 Demo (and similar) only kernel functions
/*0x8b*/ "AddLine",
/*0x8c*/ "DeleteLine",
/*0x8d*/ "UpdateLine",
diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp
index bb595e9960..534d9ce713 100644
--- a/engines/sci/engine/kevent.cpp
+++ b/engines/sci/engine/kevent.cpp
@@ -83,11 +83,12 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
}
// For a real event we use its associated mouse position
- mousePos = curEvent.mousePos;
#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
- g_sci->_gfxCoordAdjuster->fromDisplayToScript(mousePos.y, mousePos.x);
+ if (getSciVersion() >= SCI_VERSION_2)
+ mousePos = curEvent.mousePosSci;
+ else
#endif
+ mousePos = curEvent.mousePos;
// Limit the mouse cursor position, if necessary
g_sci->_gfxCursor->refreshPosition();
@@ -101,7 +102,25 @@ reg_t kGetEvent(EngineState *s, int argc, reg_t *argv) {
// question. Check GfxCursor::setPosition(), for a more detailed
// explanation and a list of cursor position workarounds.
if (s->_cursorWorkaroundRect.contains(mousePos.x, mousePos.y)) {
- s->_cursorWorkaroundActive = false;
+ // For OpenPandora and possibly other platforms, that support analog-stick control + touch screen
+ // control at the same time: in case the cursor is currently at the coordinate set by the scripts,
+ // we will count down instead of immediately disabling the workaround.
+ // On OpenPandora the cursor position is set, but it's overwritten shortly afterwards by the
+ // touch screen. In this case we would sometimes disable the workaround, simply because the touch
+ // screen hasn't yet overwritten the position and thus the workaround would not work anymore.
+ // On OpenPandora it would sometimes work and sometimes not without this.
+ if (s->_cursorWorkaroundPoint == mousePos) {
+ // Cursor is still at the same spot as set by the scripts
+ if (s->_cursorWorkaroundPosCount > 0) {
+ s->_cursorWorkaroundPosCount--;
+ } else {
+ // Was for quite a bit of time at that spot, so disable workaround now
+ s->_cursorWorkaroundActive = false;
+ }
+ } else {
+ // Cursor has moved, but is within the rect -> disable workaround immediately
+ s->_cursorWorkaroundActive = false;
+ }
} else {
mousePos.x = s->_cursorWorkaroundPoint.x;
mousePos.y = s->_cursorWorkaroundPoint.y;
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 335763a35f..4508a481a0 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -29,6 +29,7 @@
#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
+#include "common/memstream.h"
#include "gui/saveload.h"
@@ -263,19 +264,6 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
}
#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- if (s->_virtualIndexFile) {
- return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
- } else {
- Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH);
- Common::String wrappedName = g_sci->wrapFilename(englishName);
- if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) {
- s->_virtualIndexFile = new VirtualIndexFile(wrappedName);
- return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
- }
- }
- }
-
// Shivers is trying to store savegame descriptions and current spots in
// separate .SG files, which are hardcoded in the scripts.
// Essentially, there is a normal save file, created by the executable
@@ -313,18 +301,18 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
listSavegames(saves);
int savegameNr = findSavegame(saves, slotNumber - SAVEGAMEID_OFFICIALRANGE_START);
- if (!s->_virtualIndexFile) {
- // Make the virtual file buffer big enough to avoid having it grow dynamically.
- // 50 bytes should be more than enough.
- s->_virtualIndexFile = new VirtualIndexFile(50);
- }
+ int size = strlen(saves[savegameNr].name) + 2;
+ char *buf = (char *)malloc(size);
+ strcpy(buf, saves[savegameNr].name);
+ buf[size - 1] = 0; // Spot description (empty)
+
+ uint handle = findFreeFileHandle(s);
- s->_virtualIndexFile->seek(0, SEEK_SET);
- s->_virtualIndexFile->write(saves[savegameNr].name, strlen(saves[savegameNr].name));
- s->_virtualIndexFile->write("\0", 1);
- s->_virtualIndexFile->write("\0", 1); // Spot description (empty)
- s->_virtualIndexFile->seek(0, SEEK_SET);
- return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
+ s->_fileHandles[handle]._in = new Common::MemoryReadStream((byte *)buf, size, DisposeAfterUse::YES);
+ s->_fileHandles[handle]._out = nullptr;
+ s->_fileHandles[handle]._name = "";
+
+ return make_reg(0, handle);
}
}
#endif
@@ -349,13 +337,6 @@ reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
uint16 handle = argv[0].toUint16();
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- s->_virtualIndexFile->close();
- return SIGNAL_REG;
- }
-#endif
-
if (handle >= VIRTUALFILE_HANDLE_START) {
// it's a virtual handle? ignore it
return SIGNAL_REG;
@@ -381,17 +362,9 @@ reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) {
char *buf = new char[size];
debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size);
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- bytesRead = s->_virtualIndexFile->read(buf, size);
- } else {
-#endif
- FileHandle *f = getFileFromHandle(s, handle);
- if (f)
- bytesRead = f->_in->read(buf, size);
-#ifdef ENABLE_SCI32
- }
-#endif
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f)
+ bytesRead = f->_in->read(buf, size);
// TODO: What happens if less bytes are read than what has
// been requested? (i.e. if bytesRead is non-zero, but still
@@ -411,20 +384,11 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
s->_segMan->memcpy((byte *)buf, argv[1], size);
debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size);
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- s->_virtualIndexFile->write(buf, size);
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f) {
+ f->_out->write(buf, size);
success = true;
- } else {
-#endif
- FileHandle *f = getFileFromHandle(s, handle);
- if (f) {
- f->_out->write(buf, size);
- success = true;
- }
-#ifdef ENABLE_SCI32
}
-#endif
delete[] buf;
if (success)
@@ -463,13 +427,6 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
const Common::String wrappedName = g_sci->wrapFilename(name);
result = saveFileMan->removeSavefile(wrappedName);
}
-
-#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- delete s->_virtualIndexFile;
- s->_virtualIndexFile = 0;
- }
-#endif
} else {
const Common::String wrappedName = g_sci->wrapFilename(name);
result = saveFileMan->removeSavefile(wrappedName);
@@ -488,12 +445,7 @@ reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize);
uint32 bytesRead;
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE)
- bytesRead = s->_virtualIndexFile->readLine(buf, maxsize);
- else
-#endif
- bytesRead = fgets_wrapper(s, buf, maxsize, handle);
+ bytesRead = fgets_wrapper(s, buf, maxsize, handle);
s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
delete[] buf;
@@ -520,13 +472,6 @@ reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE) {
- s->_virtualIndexFile->write(str.c_str(), str.size());
- return NULL_REG;
- }
-#endif
-
FileHandle *f = getFileFromHandle(s, handle);
if (f) {
@@ -547,11 +492,6 @@ reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
uint16 whence = argv[2].toUint16();
debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence);
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE_SCI32SAVE)
- return make_reg(0, s->_virtualIndexFile->seek(offset, whence));
-#endif
-
FileHandle *f = getFileFromHandle(s, handle);
if (f && f->_in) {
@@ -591,14 +531,6 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) {
reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
Common::String name = s->_segMan->getString(argv[0]);
-#ifdef ENABLE_SCI32
- // Cache the file existence result for the Phantasmagoria
- // save index file, as the game scripts keep checking for
- // its existence.
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile)
- return TRUE_REG;
-#endif
-
bool exists = false;
if (g_sci->getGameId() == GID_PEPPER) {
@@ -611,6 +543,9 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
}
+ // TODO: It may apparently be worth caching the existence of
+ // phantsg.dir, and possibly even keeping it open persistently
+
// Check for regular file
exists = Common::File::exists(name);
@@ -806,25 +741,47 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
} else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) {
// virtualId is low, we assume that scripts expect us to create new slot
- if (g_sci->getGameId() == GID_JONES) {
+ switch (g_sci->getGameId()) {
+ case GID_JONES:
// Jones has one save slot only
savegameId = 0;
- } else if (virtualId == s->_lastSaveVirtualId) {
- // if last virtual id is the same as this one, we assume that caller wants to overwrite last save
- savegameId = s->_lastSaveNewId;
- } else {
- uint savegameNr;
- // savegameId is in lower range, scripts expect us to create a new slot
- for (savegameId = SAVEGAMESLOT_FIRST; savegameId <= SAVEGAMESLOT_LAST; savegameId++) {
- for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
- if (savegameId == saves[savegameNr].id)
+ break;
+ case GID_FANMADE: {
+ // Fanmade game, try to identify the game
+ const char *gameName = g_sci->getGameObjectName();
+
+ if (strcmp(gameName, "CascadeQuest") == 0) {
+ // Cascade Quest calls us directly to auto-save and uses slot 99,
+ // put that save into slot 0 (ScummVM auto-save slot) see bug #7007
+ if (virtualId == (SAVEGAMEID_OFFICIALRANGE_START - 1)) {
+ savegameId = 0;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (savegameId < 0) {
+ // savegameId not set yet
+ if (virtualId == s->_lastSaveVirtualId) {
+ // if last virtual id is the same as this one, we assume that caller wants to overwrite last save
+ savegameId = s->_lastSaveNewId;
+ } else {
+ uint savegameNr;
+ // savegameId is in lower range, scripts expect us to create a new slot
+ for (savegameId = SAVEGAMESLOT_FIRST; savegameId <= SAVEGAMESLOT_LAST; savegameId++) {
+ for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
+ if (savegameId == saves[savegameNr].id)
+ break;
+ }
+ if (savegameNr == saves.size()) // Slot not found, seems to be good to go
break;
}
- if (savegameNr == saves.size()) // Slot not found, seems to be good to go
- break;
+ if (savegameId > SAVEGAMESLOT_LAST)
+ error("kSavegame: no more savegame slots available");
}
- if (savegameId > SAVEGAMESLOT_LAST)
- error("kSavegame: no more savegame slots available");
}
} else {
error("kSaveGame: invalid savegameId used");
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 91d241fb79..cae5a09789 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -45,6 +45,7 @@
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/ports.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/text16.h"
#include "sci/graphics/view.h"
@@ -359,12 +360,7 @@ reg_t kTextSize(EngineState *s, int argc, reg_t *argv) {
uint16 languageSplitter = 0;
Common::String splitText = g_sci->strSplitLanguage(text.c_str(), &languageSplitter, sep);
-#ifdef ENABLE_SCI32
- if (g_sci->_gfxText32)
- g_sci->_gfxText32->kernelTextSize(splitText.c_str(), font_nr, maxwidth, &textWidth, &textHeight);
- else
-#endif
- g_sci->_gfxText16->kernelTextSize(splitText.c_str(), languageSplitter, font_nr, maxwidth, &textWidth, &textHeight);
+ g_sci->_gfxText16->kernelTextSize(splitText.c_str(), languageSplitter, font_nr, maxwidth, &textWidth, &textHeight);
// One of the game texts in LB2 German contains loads of spaces in
// its end. We trim the text here, otherwise the graphics code will
@@ -445,8 +441,15 @@ reg_t kCantBeHere(EngineState *s, int argc, reg_t *argv) {
reg_t curObject = argv[0];
reg_t listReference = (argc > 1) ? argv[1] : NULL_REG;
- reg_t canBeHere = g_sci->_gfxCompare->kernelCanBeHere(curObject, listReference);
- return canBeHere;
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ return g_sci->_gfxCompare->kernelCantBeHere32(curObject, listReference);
+ } else {
+#endif
+ return g_sci->_gfxCompare->kernelCanBeHere(curObject, listReference);
+#ifdef ENABLE_SCI32
+ }
+#endif
}
reg_t kIsItSkip(EngineState *s, int argc, reg_t *argv) {
@@ -576,9 +579,17 @@ reg_t kBaseSetter(EngineState *s, int argc, reg_t *argv) {
}
reg_t kSetNowSeen(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxCompare->kernelSetNowSeen(argv[0]);
-
- return s->r_acc;
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ g_sci->_gfxFrameout->kernelSetNowSeen(argv[0]);
+ return NULL_REG;
+ } else {
+#endif
+ g_sci->_gfxCompare->kernelSetNowSeen(argv[0]);
+ return s->r_acc;
+#ifdef ENABLE_SCI32
+ }
+#endif
}
reg_t kPalette(EngineState *s, int argc, reg_t *argv) {
@@ -1253,16 +1264,16 @@ reg_t kRemapColors(EngineState *s, int argc, reg_t *argv) {
switch (operation) {
case 0: { // remap by percent
uint16 percent = argv[1].toUint16();
- g_sci->_gfxPalette16->resetRemapping();
- g_sci->_gfxPalette16->setRemappingPercent(254, percent);
+ g_sci->_gfxRemap16->resetRemapping();
+ g_sci->_gfxRemap16->setRemappingPercent(254, percent);
}
break;
case 1: { // remap by range
uint16 from = argv[1].toUint16();
uint16 to = argv[2].toUint16();
uint16 base = argv[3].toUint16();
- g_sci->_gfxPalette16->resetRemapping();
- g_sci->_gfxPalette16->setRemappingRange(254, from, to, base);
+ g_sci->_gfxRemap16->resetRemapping();
+ g_sci->_gfxRemap16->setRemappingRange(254, from, to, base);
}
break;
case 2: // turn remapping off (unused)
diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp
index 4d48ae4e99..9cfe53255b 100644
--- a/engines/sci/engine/kgraphics32.cpp
+++ b/engines/sci/engine/kgraphics32.cpp
@@ -26,8 +26,6 @@
#include "graphics/cursorman.h"
#include "graphics/surface.h"
-#include "gui/message.h"
-
#include "sci/sci.h"
#include "sci/event.h"
#include "sci/resource.h"
@@ -45,15 +43,19 @@
#include "sci/graphics/paint16.h"
#include "sci/graphics/picture.h"
#include "sci/graphics/ports.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/text16.h"
#include "sci/graphics/view.h"
#ifdef ENABLE_SCI32
-#include "sci/graphics/palette32.h"
+#include "sci/graphics/celobj32.h"
#include "sci/graphics/controls32.h"
#include "sci/graphics/font.h" // TODO: remove once kBitmap is moved in a separate class
-#include "sci/graphics/text32.h"
#include "sci/graphics/frameout.h"
+#include "sci/graphics/paint32.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
+#include "sci/graphics/text32.h"
#endif
namespace Sci {
@@ -62,59 +64,59 @@ namespace Sci {
extern void showScummVMDialog(const Common::String &message);
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv) {
- // Returns 0 if the screen width or height is less than 640 or 400,
- // respectively.
- if (g_system->getWidth() < 640 || g_system->getHeight() < 400)
+ const Buffer &buffer = g_sci->_gfxFrameout->getCurrentBuffer();
+ if (buffer.screenWidth < 640 || buffer.screenHeight < 400)
return make_reg(0, 0);
return make_reg(0, 1);
}
-// SCI32 variant, can't work like sci16 variants
-reg_t kCantBeHere32(EngineState *s, int argc, reg_t *argv) {
- // TODO
-// reg_t curObject = argv[0];
-// reg_t listReference = (argc > 1) ? argv[1] : NULL_REG;
-
- return NULL_REG;
-}
-
reg_t kAddScreenItem(EngineState *s, int argc, reg_t *argv) {
- debugC(6, kDebugLevelGraphics, "kAddScreenItem %x:%x (%s)", argv[0].getSegment(), argv[0].getOffset(), g_sci->getEngineState()->_segMan->getObjectName(argv[0]));
+ debugC(6, kDebugLevelGraphics, "kAddScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelAddScreenItem(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv) {
- debugC(7, kDebugLevelGraphics, "kUpdateScreenItem %x:%x (%s)", argv[0].getSegment(), argv[0].getOffset(), g_sci->getEngineState()->_segMan->getObjectName(argv[0]));
+ debugC(7, kDebugLevelGraphics, "kUpdateScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelUpdateScreenItem(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv) {
- debugC(6, kDebugLevelGraphics, "kDeleteScreenItem %x:%x (%s)", argv[0].getSegment(), argv[0].getOffset(), g_sci->getEngineState()->_segMan->getObjectName(argv[0]));
+ debugC(6, kDebugLevelGraphics, "kDeleteScreenItem %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelDeleteScreenItem(argv[0]);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv) {
- debugC(6, kDebugLevelGraphics, "kAddPlane %x:%x (%s)", argv[0].getSegment(), argv[0].getOffset(), g_sci->getEngineState()->_segMan->getObjectName(argv[0]));
+ debugC(6, kDebugLevelGraphics, "kAddPlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelAddPlane(argv[0]);
return s->r_acc;
}
reg_t kUpdatePlane(EngineState *s, int argc, reg_t *argv) {
- debugC(7, kDebugLevelGraphics, "kUpdatePlane %x:%x (%s)", argv[0].getSegment(), argv[0].getOffset(), g_sci->getEngineState()->_segMan->getObjectName(argv[0]));
+ debugC(7, kDebugLevelGraphics, "kUpdatePlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelUpdatePlane(argv[0]);
return s->r_acc;
}
reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv) {
- debugC(6, kDebugLevelGraphics, "kDeletePlane %x:%x (%s)", argv[0].getSegment(), argv[0].getOffset(), g_sci->getEngineState()->_segMan->getObjectName(argv[0]));
+ debugC(6, kDebugLevelGraphics, "kDeletePlane %x:%x (%s)", PRINT_REG(argv[0]), s->_segMan->getObjectName(argv[0]));
g_sci->_gfxFrameout->kernelDeletePlane(argv[0]);
return s->r_acc;
}
+reg_t kMovePlaneItems(EngineState *s, int argc, reg_t *argv) {
+ const reg_t plane = argv[0];
+ const int16 deltaX = argv[1].toSint16();
+ const int16 deltaY = argv[2].toSint16();
+ const bool scrollPics = argc > 3 ? argv[3].toUint16() : false;
+
+ g_sci->_gfxFrameout->kernelMovePlaneItems(plane, deltaX, deltaY, scrollPics);
+ return s->r_acc;
+}
+
reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
reg_t planeObj = argv[0];
GuiResourceId pictureId = argv[1].toUint16();
@@ -123,7 +125,7 @@ reg_t kAddPicAt(EngineState *s, int argc, reg_t *argv) {
bool mirrorX = argc > 4 ? argv[4].toSint16() : false;
g_sci->_gfxFrameout->kernelAddPicAt(planeObj, pictureId, x, y, mirrorX);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
@@ -132,15 +134,13 @@ reg_t kGetHighPlanePri(EngineState *s, int argc, reg_t *argv) {
reg_t kFrameOut(EngineState *s, int argc, reg_t *argv) {
bool showBits = argc > 0 ? argv[0].toUint16() : true;
- g_sci->_gfxFrameout->kernelFrameout(showBits);
- s->speedThrottler(16);
- s->_throttleTrigger = true;
- return NULL_REG;
+ g_sci->_gfxFrameout->kernelFrameOut(showBits);
+ return s->r_acc;
}
reg_t kSetPalStyleRange(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxFrameout->kernelSetPalStyleRange(argv[0].toUint16(), argv[1].toUint16());
- return NULL_REG;
+ return s->r_acc;
}
reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) {
@@ -149,14 +149,13 @@ reg_t kObjectIntersect(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, objRect1.intersects(objRect2));
}
-// Tests if the coordinate is on the passed object
reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) {
- uint16 x = argv[0].toUint16();
- uint16 y = argv[1].toUint16();
- reg_t targetObject = argv[2];
- uint16 checkPixels = argv[3].getOffset();
+ int16 x = argv[0].toSint16();
+ int16 y = argv[1].toSint16();
+ reg_t object = argv[2];
+ bool checkPixel = argv[3].toSint16();
- return make_reg(0, g_sci->_gfxFrameout->kernelIsOnMe(x, y, checkPixels, targetObject));
+ return g_sci->_gfxFrameout->kernelIsOnMe(object, Common::Point(x, y), checkPixel);
}
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
@@ -196,24 +195,49 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
if (subop == 0) {
TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode));
- reg_t out;
- return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, 1, &out);
+ return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, true);
} else {
CelInfo32 celInfo;
celInfo.type = kCelTypeView;
celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view));
celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));
- reg_t out;
- return g_sci->_gfxText32->createTitledFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed, &out);
+ return g_sci->_gfxText32->createFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed);
}
}
-reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) {
- g_sci->_gfxText32->disposeTextBitmap(argv[0]);
+reg_t kText(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
+reg_t kTextSize32(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_gfxText32->setFont(argv[2].toUint16());
+
+ reg_t *rect = s->_segMan->derefRegPtr(argv[0], 4);
+ if (rect == nullptr) {
+ error("kTextSize: %04x:%04x cannot be dereferenced", PRINT_REG(argv[0]));
+ }
+
+ Common::String text = s->_segMan->getString(argv[1]);
+ int16 maxWidth = argc > 3 ? argv[3].toSint16() : 0;
+ bool doScaling = argc > 4 ? argv[4].toSint16() : true;
+
+ Common::Rect textRect = g_sci->_gfxText32->getTextSize(text, maxWidth, doScaling);
+ rect[0] = make_reg(0, textRect.left);
+ rect[1] = make_reg(0, textRect.top);
+ rect[2] = make_reg(0, textRect.right - 1);
+ rect[3] = make_reg(0, textRect.bottom - 1);
return s->r_acc;
}
+reg_t kTextWidth(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_gfxText32->setFont(argv[1].toUint16());
+ Common::String text = s->_segMan->getString(argv[0]);
+ return make_reg(0, g_sci->_gfxText32->getStringWidth(text));
+}
+
reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case 1:
@@ -231,6 +255,10 @@ reg_t kWinHelp(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
+reg_t kMessageBox(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_gfxControls32->kernelMessageBox(s->_segMan->getString(argv[0]), s->_segMan->getString(argv[1]), argv[2].toUint16());
+}
+
/**
* Causes an immediate plane transition with an optional transition
* effect
@@ -284,31 +312,50 @@ reg_t kSetShowStyle(EngineState *s, int argc, reg_t *argv) {
// on the KernelMgr
g_sci->_gfxFrameout->kernelSetShowStyle(argc, planeObj, type, seconds, back, priority, animate, refFrame, pFadeArray, divisions, blackScreen);
- return NULL_REG;
+ return s->r_acc;
+}
+
+reg_t kCelHigh32(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId resourceId = argv[0].toUint16();
+ int16 loopNo = argv[1].toSint16();
+ int16 celNo = argv[2].toSint16();
+ CelObjView celObj(resourceId, loopNo, celNo);
+ return make_reg(0, mulru(celObj._height, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, celObj._scaledHeight)));
+}
+
+reg_t kCelWide32(EngineState *s, int argc, reg_t *argv) {
+ GuiResourceId resourceId = argv[0].toUint16();
+ int16 loopNo = argv[1].toSint16();
+ int16 celNo = argv[2].toSint16();
+ CelObjView celObj(resourceId, loopNo, celNo);
+ return make_reg(0, mulru(celObj._width, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, celObj._scaledWidth)));
}
reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) {
// Used by Shivers 1, room 23601 to determine what blocks on the red door puzzle board
// are occupied by pieces already
- switch (argv[0].toUint16()) { // subops 0 - 4
- // 0 - return the view
- // 1 - return the loop
- // 2, 3 - nop
- case 4: {
- GuiResourceId viewId = argv[1].toSint16();
- int16 loopNo = argv[2].toSint16();
- int16 celNo = argv[3].toSint16();
- int16 x = argv[4].toUint16();
- int16 y = argv[5].toUint16();
- byte color = g_sci->_gfxCache->kernelViewGetColorAtCoordinate(viewId, loopNo, celNo, x, y);
- return make_reg(0, color);
- }
- default: {
- kStub(s, argc, argv);
- return s->r_acc;
- }
+ CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16());
+
+ int16 result = 0;
+
+ switch (argv[0].toUint16()) {
+ case 0:
+ result = view._displace.x;
+ break;
+ case 1:
+ result = view._displace.y;
+ break;
+ case 2:
+ case 3:
+ // null operation
+ break;
+ case 4:
+ result = view.readPixel(argv[4].toSint16(), argv[5].toSint16(), view._mirrorX);
+ break;
}
+
+ return make_reg(0, result);
}
reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
@@ -318,391 +365,399 @@ reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
}
reg_t kScrollWindowCreate(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowCreate");
- kStub(s, argc, argv);
- return argv[0];
+ const reg_t object = argv[0];
+ const uint16 maxNumEntries = argv[1].toUint16();
+
+ SegManager *segMan = s->_segMan;
+ const int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor));
+ const TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode));
+ const GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font));
+ const int16 backColor = readSelectorValue(segMan, object, SELECTOR(back));
+ const int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore));
+ const reg_t plane = readSelector(segMan, object, SELECTOR(plane));
+
+ Common::Rect rect;
+ rect.left = readSelectorValue(segMan, object, SELECTOR(nsLeft));
+ rect.top = readSelectorValue(segMan, object, SELECTOR(nsTop));
+ rect.right = readSelectorValue(segMan, object, SELECTOR(nsRight)) + 1;
+ rect.bottom = readSelectorValue(segMan, object, SELECTOR(nsBottom)) + 1;
+ const Common::Point position(rect.left, rect.top);
+
+ return g_sci->_gfxControls32->makeScrollWindow(rect, position, plane, foreColor, backColor, fontId, alignment, borderColor, maxNumEntries);
}
reg_t kScrollWindowAdd(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowAdd");
- return kStubNull(s, argc, argv);
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const Common::String text = s->_segMan->getString(argv[1]);
+ const GuiResourceId fontId = argv[2].toSint16();
+ const int16 color = argv[3].toSint16();
+ const TextAlign alignment = (TextAlign)argv[4].toSint16();
+ const bool scrollTo = argc > 5 ? (bool)argv[5].toUint16() : true;
+
+ return scrollWindow->add(text, fontId, color, alignment, scrollTo);
}
reg_t kScrollWindowWhere(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowWhere");
- return kStubNull(s, argc, argv);
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const uint16 where = (argv[1].toUint16() * scrollWindow->where()).toInt();
+
+ return make_reg(0, where);
+}
+
+reg_t kScrollWindowGo(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const Ratio scrollTop(argv[1].toSint16(), argv[2].toSint16());
+ scrollWindow->go(scrollTop);
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowModify(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ const reg_t entryId = argv[1];
+ const Common::String newText = s->_segMan->getString(argv[2]);
+ const GuiResourceId fontId = argv[3].toSint16();
+ const int16 color = argv[4].toSint16();
+ const TextAlign alignment = (TextAlign)argv[5].toSint16();
+ const bool scrollTo = argc > 6 ? (bool)argv[6].toUint16() : true;
+
+ return scrollWindow->modify(entryId, newText, fontId, color, alignment, scrollTo);
+}
+
+reg_t kScrollWindowHide(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->hide();
+
+ return s->r_acc;
}
reg_t kScrollWindowShow(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowShow");
- return kStubNull(s, argc, argv);
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->show();
+
+ return s->r_acc;
}
-reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv) {
- debug("kScrollWindowDestroy");
- return kStubNull(s, argc, argv);
+reg_t kScrollWindowPageUp(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->pageUp();
+
+ return s->r_acc;
}
-#if 0
-reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
- // Used by SQ6 and LSL6 hires for the text area in the bottom of the
- // screen. The relevant scripts also exist in Phantasmagoria 1, but they're
- // unused. This is always called by scripts 64906 (ScrollerWindow) and
- // 64907 (ScrollableWindow).
-
- reg_t kWindow = argv[1];
- uint16 op = argv[0].toUint16();
- switch (op) {
- case 0: // Init
- // TODO: Init reads the nsLeft, nsTop, nsRight, nsBottom,
- // borderColor, fore, back, mode, font, plane selectors
- // from the window in argv[1].
- g_sci->_gfxFrameout->initScrollText(argv[2].toUint16()); // maxItems
- g_sci->_gfxFrameout->clearScrollTexts();
- return argv[1]; // kWindow
- case 1: // Show message, called by ScrollableWindow::addString
- case 14: // Modify message, called by ScrollableWindow::modifyString
- // TODO: The parameters in Modify are shifted by one: the first
- // argument is the handle of the text to modify. The others
- // are as Add.
- {
- Common::String text = s->_segMan->getString(argv[2]);
- uint16 x = 0;
- uint16 y = 0;
- // TODO: argv[3] is font
- // TODO: argv[4] is color
- // TODO: argv[5] is alignment (0 = left, 1 = center, 2 = right)
- // font,color,alignment may also be -1. (Maybe same as previous?)
- // TODO: argv[6] is an optional bool, defaulting to true if not present.
- // If true, the old contents are scrolled out of view.
- // TODO: Return a handle of the inserted text. (Used for modify/insert)
- // This handle looks like it should also be usable by kString.
- g_sci->_gfxFrameout->addScrollTextEntry(text, kWindow, x, y, (op == 14));
- }
- break;
- case 2: // Clear, called by ScrollableWindow::erase
- g_sci->_gfxFrameout->clearScrollTexts();
- break;
- case 3: // Page up, called by ScrollableWindow::scrollTo
- // TODO
- kStub(s, argc, argv);
- break;
- case 4: // Page down, called by ScrollableWindow::scrollTo
- // TODO
- kStub(s, argc, argv);
- break;
- case 5: // Up arrow, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->prevScrollText();
- break;
- case 6: // Down arrow, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->nextScrollText();
- break;
- case 7: // Home, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->firstScrollText();
- break;
- case 8: // End, called by ScrollableWindow::scrollTo
- g_sci->_gfxFrameout->lastScrollText();
- break;
- case 9: // Resize, called by ScrollableWindow::resize and ScrollerWindow::resize
- // TODO: This reads the nsLeft, nsTop, nsRight, nsBottom
- // selectors from the SCI object passed in argv[2].
- kStub(s, argc, argv);
- break;
- case 10: // Where, called by ScrollableWindow::where
- // TODO:
- // Gives the current relative scroll location as a fraction
- // with argv[2] as the denominator. (Return value is the numerator.)
- // Silenced the warnings because of the high amount of console spam
- //kStub(s, argc, argv);
- break;
- case 11: // Go, called by ScrollableWindow::scrollTo
- // TODO:
- // Two arguments provide a fraction: argv[2] is num., argv[3] is denom.
- // Scrolls to the relative location given by the fraction.
- kStub(s, argc, argv);
- break;
- case 12: // Insert, called by ScrollableWindow::insertString
- // 5 extra parameters here:
- // handle of insert location (new string takes that position).
- // text, font, color, alignment
- // TODO
- kStub(s, argc, argv);
- break;
- // case 13 (Delete) is handled below
- // case 14 (Modify) is handled above
- case 15: // Hide, called by ScrollableWindow::hide
- g_sci->_gfxFrameout->toggleScrollText(false);
- break;
- case 16: // Show, called by ScrollableWindow::show
- g_sci->_gfxFrameout->toggleScrollText(true);
- break;
- case 17: // Destroy, called by ScrollableWindow::dispose
- g_sci->_gfxFrameout->clearScrollTexts();
- break;
- case 13: // Delete, unused
- case 18: // Text, unused
- case 19: // Reconstruct, unused
- error("kScrollWindow: Unused subop %d invoked", op);
- break;
- default:
- error("kScrollWindow: unknown subop %d", op);
- break;
- }
+reg_t kScrollWindowPageDown(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->pageDown();
return s->r_acc;
}
-#endif
-reg_t kFont(EngineState *s, int argc, reg_t *argv) {
- // TODO: Handle font settings for SCI2.1
+reg_t kScrollWindowUpArrow(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
- switch (argv[0].toUint16()) {
- case 1:
- g_sci->_gfxText32->_scaledWidth = argv[1].toUint16();
- g_sci->_gfxText32->_scaledHeight = argv[2].toUint16();
- return NULL_REG;
- default:
- error("kFont: unknown subop %d", argv[0].toUint16());
- }
+ scrollWindow->upArrow();
return s->r_acc;
}
+reg_t kScrollWindowDownArrow(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->downArrow();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowHome(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->home();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowEnd(EngineState *s, int argc, reg_t *argv) {
+ ScrollWindow *scrollWindow = g_sci->_gfxControls32->getScrollWindow(argv[0]);
+
+ scrollWindow->end();
+
+ return s->r_acc;
+}
+
+reg_t kScrollWindowDestroy(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_gfxControls32->destroyScrollWindow(argv[0]);
+
+ return s->r_acc;
+}
+
+reg_t kFont(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
+reg_t kSetFontHeight(EngineState *s, int argc, reg_t *argv) {
+ // TODO: Setting font may have just been for side effect
+ // of setting the fontHeight on the font manager, in
+ // which case we could just get the font directly ourselves.
+ g_sci->_gfxText32->setFont(argv[0].toUint16());
+ g_sci->_gfxText32->_scaledHeight = (g_sci->_gfxText32->_font->getHeight() * g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight + g_sci->_gfxText32->_scaledHeight - 1) / g_sci->_gfxText32->_scaledHeight;
+ return make_reg(0, g_sci->_gfxText32->_scaledHeight);
+}
+
reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxText32->_scaledWidth = argv[0].toUint16();
g_sci->_gfxText32->_scaledHeight = argv[1].toUint16();
- return NULL_REG;
+ return s->r_acc;
}
-// TODO: Eventually, all of the kBitmap operations should be put
-// in a separate class
+reg_t kBitmap(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
-// NOTE: This size is correct only for SCI2.1mid; the size for
-// SCI2/2.1early is 36
-#define BITMAP_HEADER_SIZE 46
+reg_t kBitmapCreate(EngineState *s, int argc, reg_t *argv) {
+ int16 width = argv[0].toSint16();
+ int16 height = argv[1].toSint16();
+ int16 skipColor = argv[2].toSint16();
+ int16 backColor = argv[3].toSint16();
+ int16 scaledWidth = argc > 4 ? argv[4].toSint16() : g_sci->_gfxText32->_scaledWidth;
+ int16 scaledHeight = argc > 5 ? argv[5].toSint16() : g_sci->_gfxText32->_scaledHeight;
+ bool useRemap = argc > 6 ? argv[6].toSint16() : false;
-reg_t kBitmap(EngineState *s, int argc, reg_t *argv) {
- // Used for bitmap operations in SCI2.1 and SCI3.
- // This is the SCI2.1 version, the functionality seems to have changed in SCI3.
+ BitmapResource bitmap(s->_segMan, width, height, skipColor, 0, 0, scaledWidth, scaledHeight, 0, useRemap);
+ memset(bitmap.getPixels(), backColor, width * height);
+ return bitmap.getObject();
+}
- switch (argv[0].toUint16()) {
- case 0: // init bitmap surface
- {
- // 6 params, called e.g. from TextView::init() in Torin's Passage,
- // script 64890 and TransView::init() in script 64884
- uint16 width = argv[1].toUint16();
- uint16 height = argv[2].toUint16();
- //uint16 skip = argv[3].toUint16();
- uint16 back = argv[4].toUint16(); // usually equals skip
- //uint16 width2 = (argc >= 6) ? argv[5].toUint16() : 0;
- //uint16 height2 = (argc >= 7) ? argv[6].toUint16() : 0;
- //uint16 transparentFlag = (argc >= 8) ? argv[7].toUint16() : 0;
-
- // TODO: skip, width2, height2, transparentFlag
- // (used for transparent bitmaps)
- int entrySize = width * height + BITMAP_HEADER_SIZE;
- reg_t memoryId = s->_segMan->allocateHunkEntry("Bitmap()", entrySize);
- byte *memoryPtr = s->_segMan->getHunkPointer(memoryId);
- memset(memoryPtr, 0, BITMAP_HEADER_SIZE); // zero out the bitmap header
- memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height);
- // Save totalWidth, totalHeight
- // TODO: Save the whole bitmap header, like SSCI does
- WRITE_SCI11ENDIAN_UINT16(memoryPtr, width);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 2, height);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 4, 0);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 6, 0);
- memoryPtr[8] = 0;
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 10, 0);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 20, BITMAP_HEADER_SIZE);
- WRITE_SCI11ENDIAN_UINT32(memoryPtr + 28, 46);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 36, width);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 38, width);
- return memoryId;
- }
- break;
- case 1: // dispose text bitmap surface
- return kDisposeTextBitmap(s, argc - 1, argv + 1);
- case 2: // dispose bitmap surface, with extra param
- // 2 params, called e.g. from MenuItem::dispose in Torin's Passage,
- // script 64893
- warning("kBitmap(2), unk1 %d, bitmap ptr %04x:%04x", argv[1].toUint16(), PRINT_REG(argv[2]));
- break;
- case 3: // tiled surface
- {
- // 6 params, called e.g. from TiledBitmap::resize() in Torin's Passage,
- // script 64869
- reg_t hunkId = argv[1]; // obtained from kBitmap(0)
- // The tiled view seems to always have 2 loops.
- // These loops need to have 1 cel in loop 0 and 8 cels in loop 1.
- uint16 viewNum = argv[2].toUint16(); // vTiles selector
- uint16 loop = argv[3].toUint16();
- uint16 cel = argv[4].toUint16();
- uint16 x = argv[5].toUint16();
- uint16 y = argv[6].toUint16();
-
- byte *memoryPtr = s->_segMan->getHunkPointer(hunkId);
- // Get totalWidth, totalHeight
- uint16 totalWidth = READ_LE_UINT16(memoryPtr);
- uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2);
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
-
- GfxView *view = g_sci->_gfxCache->getView(viewNum);
- uint16 tileWidth = view->getWidth(loop, cel);
- uint16 tileHeight = view->getHeight(loop, cel);
- const byte *tileBitmap = view->getBitmap(loop, cel);
- uint16 width = MIN<uint16>(totalWidth - x, tileWidth);
- uint16 height = MIN<uint16>(totalHeight - y, tileHeight);
-
- for (uint16 curY = 0; curY < height; curY++) {
- for (uint16 curX = 0; curX < width; curX++) {
- bitmap[(curY + y) * totalWidth + (curX + x)] = tileBitmap[curY * tileWidth + curX];
- }
- }
-
- }
- break;
- case 4: // add text to bitmap
- {
- // 13 params, called e.g. from TextButton::createBitmap() in Torin's Passage,
- // script 64894
- reg_t hunkId = argv[1]; // obtained from kBitmap(0)
- Common::String text = s->_segMan->getString(argv[2]);
- uint16 textX = argv[3].toUint16();
- uint16 textY = argv[4].toUint16();
- //reg_t unk5 = argv[5];
- //reg_t unk6 = argv[6];
- //reg_t unk7 = argv[7]; // skip?
- //reg_t unk8 = argv[8]; // back?
- //reg_t unk9 = argv[9];
- uint16 fontId = argv[10].toUint16();
- //uint16 mode = argv[11].toUint16();
- uint16 dimmed = argv[12].toUint16();
- //warning("kBitmap(4): bitmap ptr %04x:%04x, font %d, mode %d, dimmed %d - text: \"%s\"",
- // PRINT_REG(bitmapPtr), font, mode, dimmed, text.c_str());
- uint16 foreColor = 255; // TODO
-
- byte *memoryPtr = s->_segMan->getHunkPointer(hunkId);
- // Get totalWidth, totalHeight
- uint16 totalWidth = READ_LE_UINT16(memoryPtr);
- uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2);
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
-
- GfxFont *font = g_sci->_gfxCache->getFont(fontId);
-
- int16 charCount = 0;
- uint16 curX = textX, curY = textY;
- const char *txt = text.c_str();
-
- while (*txt) {
- charCount = g_sci->_gfxText32->GetLongest(txt, totalWidth, font);
- if (charCount == 0)
- break;
-
- for (int i = 0; i < charCount; i++) {
- unsigned char curChar = txt[i];
- font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, totalWidth, totalHeight);
- curX += font->getCharWidth(curChar);
- }
-
- curX = textX;
- curY += font->getHeight();
- txt += charCount;
- while (*txt == ' ')
- txt++; // skip over breaking spaces
- }
-
- }
- break;
- case 5: // fill with color
- {
- // 6 params, called e.g. from TextView::init() and TextView::draw()
- // in Torin's Passage, script 64890
- reg_t hunkId = argv[1]; // obtained from kBitmap(0)
- uint16 x = argv[2].toUint16();
- uint16 y = argv[3].toUint16();
- uint16 fillWidth = argv[4].toUint16(); // width - 1
- uint16 fillHeight = argv[5].toUint16(); // height - 1
- uint16 back = argv[6].toUint16();
-
- byte *memoryPtr = s->_segMan->getHunkPointer(hunkId);
- // Get totalWidth, totalHeight
- uint16 totalWidth = READ_LE_UINT16(memoryPtr);
- uint16 totalHeight = READ_LE_UINT16(memoryPtr + 2);
- uint16 width = MIN<uint16>(totalWidth - x, fillWidth);
- uint16 height = MIN<uint16>(totalHeight - y, fillHeight);
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
-
- for (uint16 curY = 0; curY < height; curY++) {
- for (uint16 curX = 0; curX < width; curX++) {
- bitmap[(curY + y) * totalWidth + (curX + x)] = back;
- }
- }
-
- }
- break;
- default:
- kStub(s, argc, argv);
- break;
- }
+reg_t kBitmapDestroy(EngineState *s, int argc, reg_t *argv) {
+ s->_segMan->freeHunkEntry(argv[0]);
+ return s->r_acc;
+}
+reg_t kBitmapDrawLine(EngineState *s, int argc, reg_t *argv) {
+ // bitmapMemId, (x1, y1, x2, y2) OR (x2, y2, x1, y1), line color, unknown int, unknown int
+ return kStubNull(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapDrawView(EngineState *s, int argc, reg_t *argv) {
+ BitmapResource bitmap(argv[0]);
+ CelObjView view(argv[1].toUint16(), argv[2].toSint16(), argv[3].toSint16());
+
+ const int16 x = argc > 4 ? argv[4].toSint16() : 0;
+ const int16 y = argc > 5 ? argv[5].toSint16() : 0;
+ const int16 alignX = argc > 7 ? argv[7].toSint16() : -1;
+ const int16 alignY = argc > 8 ? argv[8].toSint16() : -1;
+
+ Common::Point position(
+ x == -1 ? bitmap.getDisplace().x : x,
+ y == -1 ? bitmap.getDisplace().y : y
+ );
+
+ position.x -= alignX == -1 ? view._displace.x : alignX;
+ position.y -= alignY == -1 ? view._displace.y : alignY;
+
+ Common::Rect drawRect(
+ position.x,
+ position.y,
+ position.x + view._width,
+ position.y + view._height
+ );
+ drawRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight()));
+ view.draw(bitmap.getBuffer(), drawRect, position, view._mirrorX);
return s->r_acc;
}
-// Used for edit boxes in save/load dialogs. It's a rewritten version of kEditControl,
-// but it handles events on its own, using an internal loop, instead of using SCI
-// scripts for event management like kEditControl does. Called by script 64914,
-// DEdit::hilite().
-reg_t kEditText(EngineState *s, int argc, reg_t *argv) {
- reg_t controlObject = argv[0];
+reg_t kBitmapDrawText(EngineState *s, int argc, reg_t *argv) {
+ // called e.g. from TextButton::createBitmap() in Torin's Passage, script 64894
- if (!controlObject.isNull()) {
- g_sci->_gfxControls32->kernelTexteditChange(controlObject);
- }
+ BitmapResource bitmap(argv[0]);
+ Common::String text = s->_segMan->getString(argv[1]);
+ Common::Rect textRect(
+ argv[2].toSint16(),
+ argv[3].toSint16(),
+ argv[4].toSint16() + 1,
+ argv[5].toSint16() + 1
+ );
+ int16 foreColor = argv[6].toSint16();
+ int16 backColor = argv[7].toSint16();
+ int16 skipColor = argv[8].toSint16();
+ GuiResourceId fontId = (GuiResourceId)argv[9].toUint16();
+ TextAlign alignment = (TextAlign)argv[10].toSint16();
+ int16 borderColor = argv[11].toSint16();
+ bool dimmed = argv[12].toUint16();
+
+ // NOTE: Technically the engine checks these things:
+ // textRect.bottom > 0
+ // textRect.right > 0
+ // textRect.left < bitmap.width
+ // textRect.top < bitmap.height
+ // Then clips. But this seems stupid.
+ textRect.clip(Common::Rect(bitmap.getWidth(), bitmap.getHeight()));
+
+ reg_t textBitmapObject = g_sci->_gfxText32->createFontBitmap(textRect.width(), textRect.height(), Common::Rect(textRect.width(), textRect.height()), text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, false);
+ CelObjMem textCel(textBitmapObject);
+ textCel.draw(bitmap.getBuffer(), textRect, Common::Point(textRect.left, textRect.top), false);
+ s->_segMan->freeHunkEntry(textBitmapObject);
return s->r_acc;
}
-reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
- return kStubNull(s, argc, argv); // return 0:0 for now, so that follow up calls won't create signature mismatches
-#if 0
- reg_t plane = argv[0];
- Common::Point startPoint(argv[1].toUint16(), argv[2].toUint16());
- Common::Point endPoint(argv[3].toUint16(), argv[4].toUint16());
- // argv[5] is unknown (a number, usually 200)
- byte color = (byte)argv[6].toUint16();
- byte priority = (byte)argv[7].toUint16();
- byte control = (byte)argv[8].toUint16();
- // argv[9] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
-// return g_sci->_gfxFrameout->addPlaneLine(plane, startPoint, endPoint, color, priority, control);
+reg_t kBitmapDrawColor(EngineState *s, int argc, reg_t *argv) {
+ // called e.g. from TextView::init() and TextView::draw() in Torin's Passage, script 64890
+
+ BitmapResource bitmap(argv[0]);
+ Common::Rect fillRect(
+ argv[1].toSint16(),
+ argv[2].toSint16(),
+ argv[3].toSint16() + 1,
+ argv[4].toSint16() + 1
+ );
+
+ bitmap.getBuffer().fillRect(fillRect, argv[5].toSint16());
return s->r_acc;
-#endif
+}
+
+reg_t kBitmapDrawBitmap(EngineState *s, int argc, reg_t *argv) {
+ // target bitmap, source bitmap, x, y, unknown boolean
+
+ return kStubNull(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapInvert(EngineState *s, int argc, reg_t *argv) {
+ // bitmap, left, top, right, bottom, foreColor, backColor
+
+ return kStubNull(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapSetDisplace(EngineState *s, int argc, reg_t *argv) {
+ BitmapResource bitmap(argv[0]);
+ bitmap.setDisplace(Common::Point(argv[1].toSint16(), argv[2].toSint16()));
+ return s->r_acc;
+}
+
+reg_t kBitmapCreateFromView(EngineState *s, int argc, reg_t *argv) {
+ // viewId, loopNo, celNo, skipColor, backColor, useRemap, source overlay bitmap
+
+ return kStub(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapCopyPixels(EngineState *s, int argc, reg_t *argv) {
+ // target bitmap, source bitmap
+
+ return kStubNull(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapClone(EngineState *s, int argc, reg_t *argv) {
+ // bitmap
+
+ return kStub(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapGetInfo(EngineState *s, int argc, reg_t *argv) {
+ // bitmap
+
+ // argc 1 = get width
+ // argc 2 = pixel at row 0 col n
+ // argc 3 = pixel at row n col n
+ return kStub(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapScale(EngineState *s, int argc, reg_t *argv) {
+ // TODO: SCI3
+ return kStubNull(s, argc + 1, argv - 1);
+}
+
+reg_t kBitmapCreateFromUnknown(EngineState *s, int argc, reg_t *argv) {
+ // TODO: SCI3
+ return kStub(s, argc + 1, argv - 1);
+}
+
+reg_t kEditText(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_gfxControls32->kernelEditText(argv[0]);
+}
+
+reg_t kAddLine(EngineState *s, int argc, reg_t *argv) {
+ const reg_t plane = argv[0];
+ const Common::Point startPoint(argv[1].toSint16(), argv[2].toSint16());
+ const Common::Point endPoint(argv[3].toSint16(), argv[4].toSint16());
+
+ int16 priority;
+ uint8 color;
+ LineStyle style;
+ uint16 pattern;
+ uint8 thickness;
+
+ if (argc == 10) {
+ priority = argv[5].toSint16();
+ color = (uint8)argv[6].toUint16();
+ style = (LineStyle)argv[7].toSint16();
+ pattern = argv[8].toUint16();
+ thickness = (uint8)argv[9].toUint16();
+ } else {
+ priority = 1000;
+ color = 255;
+ style = kLineStyleSolid;
+ pattern = 0;
+ thickness = 1;
+ }
+
+ return g_sci->_gfxPaint32->kernelAddLine(plane, startPoint, endPoint, priority, color, style, pattern, thickness);
}
reg_t kUpdateLine(EngineState *s, int argc, reg_t *argv) {
- return kStub(s, argc, argv);
+ const reg_t screenItemObject = argv[0];
+ const reg_t planeObject = argv[1];
+ const Common::Point startPoint(argv[2].toSint16(), argv[3].toSint16());
+ const Common::Point endPoint(argv[4].toSint16(), argv[5].toSint16());
+
+ int16 priority;
+ uint8 color;
+ LineStyle style;
+ uint16 pattern;
+ uint8 thickness;
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObject);
+ if (plane == nullptr) {
+ error("kUpdateLine: Plane %04x:%04x not found", PRINT_REG(planeObject));
+ }
+
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject);
+ if (screenItem == nullptr) {
+ error("kUpdateLine: Screen item %04x:%04x not found", PRINT_REG(screenItemObject));
+ }
+
+ if (argc == 11) {
+ priority = argv[6].toSint16();
+ color = (uint8)argv[7].toUint16();
+ style = (LineStyle)argv[8].toSint16();
+ pattern = argv[9].toUint16();
+ thickness = (uint8)argv[10].toUint16();
+ } else {
+ priority = screenItem->_priority;
+ color = screenItem->_celInfo.color;
+ style = kLineStyleSolid;
+ pattern = 0;
+ thickness = 1;
+ }
+
+ g_sci->_gfxPaint32->kernelUpdateLine(screenItem, plane, startPoint, endPoint, priority, color, style, pattern, thickness);
-#if 0
- reg_t hunkId = argv[0];
- reg_t plane = argv[1];
- Common::Point startPoint(argv[2].toUint16(), argv[3].toUint16());
- Common::Point endPoint(argv[4].toUint16(), argv[5].toUint16());
- // argv[6] is unknown (a number, usually 200)
- byte color = (byte)argv[7].toUint16();
- byte priority = (byte)argv[8].toUint16();
- byte control = (byte)argv[9].toUint16();
- // argv[10] is unknown (usually a small number, 1 or 2). Thickness, perhaps?
-// g_sci->_gfxFrameout->updatePlaneLine(plane, hunkId, startPoint, endPoint, color, priority, control);
return s->r_acc;
-#endif
}
+
reg_t kDeleteLine(EngineState *s, int argc, reg_t *argv) {
- return kStub(s, argc, argv);
-#if 0
- reg_t hunkId = argv[0];
- reg_t plane = argv[1];
-// g_sci->_gfxFrameout->deletePlaneLine(plane, hunkId);
+ g_sci->_gfxPaint32->kernelDeleteLine(argv[0], argv[1]);
return s->r_acc;
-#endif
}
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
@@ -732,7 +787,20 @@ reg_t kSetScroll(EngineState *s, int argc, reg_t *argv) {
// Used by SQ6, script 900, the datacorder reprogramming puzzle (from room 270)
reg_t kMorphOn(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxFrameout->_palMorphIsOn = true;
- return NULL_REG;
+ return s->r_acc;
+}
+
+reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv) {
+ const GuiResourceId paletteId = argv[0].toUint16();
+ g_sci->_gfxPalette32->loadPalette(paletteId);
+ return s->r_acc;
+}
+
+reg_t kPaletteFindColor32(EngineState *s, int argc, reg_t *argv) {
+ const uint8 r = argv[0].toUint16();
+ const uint8 g = argv[1].toUint16();
+ const uint8 b = argv[2].toUint16();
+ return make_reg(0, g_sci->_gfxPalette32->matchColor(r, g, b));
}
reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) {
@@ -740,7 +808,7 @@ reg_t kPaletteSetFade(EngineState *s, int argc, reg_t *argv) {
uint16 toColor = argv[1].toUint16();
uint16 percent = argv[2].toUint16();
g_sci->_gfxPalette32->setFade(percent, fromColor, toColor);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) {
@@ -758,14 +826,14 @@ reg_t kPalVarySetVary(EngineState *s, int argc, reg_t *argv) {
}
g_sci->_gfxPalette32->kernelPalVarySet(paletteId, percent, time, fromColor, toColor);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVarySetPercent(EngineState *s, int argc, reg_t *argv) {
int time = argc > 0 ? argv[0].toSint16() * 60 : 0;
int16 percent = argc > 1 ? argv[1].toSint16() : 0;
g_sci->_gfxPalette32->setVaryPercent(percent, time, -1, -1);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv) {
@@ -774,7 +842,7 @@ reg_t kPalVaryGetPercent(EngineState *s, int argc, reg_t *argv) {
reg_t kPalVaryOff(EngineState *s, int argc, reg_t *argv) {
g_sci->_gfxPalette32->varyOff();
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) {
@@ -786,7 +854,7 @@ reg_t kPalVaryMergeTarget(EngineState *s, int argc, reg_t *argv) {
reg_t kPalVarySetTime(EngineState *s, int argc, reg_t *argv) {
int time = argv[0].toSint16() * 60;
g_sci->_gfxPalette32->setVaryTime(time);
- return NULL_REG;
+ return s->r_acc;
}
reg_t kPalVarySetTarget(EngineState *s, int argc, reg_t *argv) {
@@ -807,140 +875,123 @@ reg_t kPalVaryMergeStart(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, g_sci->_gfxPalette32->getVaryPercent());
}
-enum {
- kSetCycle = 0,
- kDoCycle = 1,
- kCyclePause = 2,
- kCycleOn = 3,
- kCycleOff = 4
-};
-
reg_t kPalCycle(EngineState *s, int argc, reg_t *argv) {
- // Examples: GK1 room 480 (Bayou ritual), LSL6 room 100 (title screen)
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- switch (argv[0].toUint16()) {
- case kSetCycle: {
- uint16 fromColor = argv[1].toUint16();
- uint16 toColor = argv[2].toUint16();
- int16 direction = argv[3].toSint16();
- uint16 delay = (argc == 4 ? 0 : argv[4].toUint16());
-
- g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay);
- }
- break;
- case kDoCycle: {
- uint16 fromColor = argv[1].toUint16();
- int16 speed = (argc == 2) ? 1 : argv[2].toSint16();
- g_sci->_gfxPalette32->doCycle(fromColor, speed);
- }
- break;
- case kCyclePause: {
- if (argc == 1) {
- g_sci->_gfxPalette32->cycleAllPause();
- } else {
- uint16 fromColor = argv[1].toUint16();
- g_sci->_gfxPalette32->cyclePause(fromColor);
- }
- }
- break;
- case kCycleOn: {
- if (argc == 1) {
- g_sci->_gfxPalette32->cycleAllOn();
- } else {
- uint16 fromColor = argv[1].toUint16();
- g_sci->_gfxPalette32->cycleOn(fromColor);
- }
- }
- break;
- case kCycleOff: {
- if (argc == 1) {
- g_sci->_gfxPalette32->cycleAllOff();
- } else {
- uint16 fromColor = argv[1].toUint16();
- g_sci->_gfxPalette32->cycleOff(fromColor);
- }
- break;
- }
- default:
- // In SCI2.1 there are no values above 4, so should never get here;
- // SCI just returns early if this ever happens.
- assert(false);
- break;
+reg_t kPalCycleSetCycle(EngineState *s, int argc, reg_t *argv) {
+ const uint16 fromColor = argv[0].toUint16();
+ const uint16 toColor = argv[1].toUint16();
+ const int16 direction = argv[2].toSint16();
+ const uint16 delay = argc > 3 ? argv[3].toUint16() : 0;
+
+ g_sci->_gfxPalette32->setCycle(fromColor, toColor, direction, delay);
+ return s->r_acc;
+}
+
+reg_t kPalCycleDoCycle(EngineState *s, int argc, reg_t *argv) {
+ const uint16 fromColor = argv[0].toUint16();
+ const int16 speed = argc > 1 ? argv[1].toSint16() : 1;
+
+ g_sci->_gfxPalette32->doCycle(fromColor, speed);
+ return s->r_acc;
+}
+
+reg_t kPalCyclePause(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxPalette32->cycleAllPause();
+ } else {
+ const uint16 fromColor = argv[0].toUint16();
+ g_sci->_gfxPalette32->cyclePause(fromColor);
+ }
+ return s->r_acc;
+}
+
+reg_t kPalCycleOn(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxPalette32->cycleAllOn();
+ } else {
+ const uint16 fromColor = argv[0].toUint16();
+ g_sci->_gfxPalette32->cycleOn(fromColor);
}
+ return s->r_acc;
+}
+reg_t kPalCycleOff(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxPalette32->cycleAllOff();
+ } else {
+ const uint16 fromColor = argv[0].toUint16();
+ g_sci->_gfxPalette32->cycleOff(fromColor);
+ }
return s->r_acc;
}
reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) {
- uint16 operation = argv[0].toUint16();
-
- switch (operation) {
- case 0: { // turn remapping off
- // WORKAROUND: Game scripts in QFG4 erroneously turn remapping off in room
- // 140 (the character point allocation screen) and never turn it back on,
- // even if it's clearly used in that screen.
- if (g_sci->getGameId() == GID_QFG4 && s->currentRoomNumber() == 140)
- return s->r_acc;
-
- int16 base = (argc >= 2) ? argv[1].toSint16() : 0;
- if (base > 0)
- warning("kRemapColors(0) called with base %d", base);
- g_sci->_gfxPalette32->resetRemapping();
- }
- break;
- case 1: { // remap by range
- uint16 color = argv[1].toUint16();
- uint16 from = argv[2].toUint16();
- uint16 to = argv[3].toUint16();
- uint16 base = argv[4].toUint16();
- uint16 unk5 = (argc >= 6) ? argv[5].toUint16() : 0;
- if (unk5 > 0)
- warning("kRemapColors(1) called with 6 parameters, unknown parameter is %d", unk5);
- g_sci->_gfxPalette32->setRemappingRange(color, from, to, base);
- }
- break;
- case 2: { // remap by percent
- uint16 color = argv[1].toUint16();
- uint16 percent = argv[2].toUint16(); // 0 - 100
- if (argc >= 4)
- warning("RemapByPercent called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
- g_sci->_gfxPalette32->setRemappingPercent(color, percent);
- }
- break;
- case 3: { // remap to gray
- // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0.
- // In this room, it's used for the cloud before Baba Yaga appears.
- int16 color = argv[1].toSint16();
- int16 percent = argv[2].toSint16(); // 0 - 100
- if (argc >= 4)
- warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16());
- g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
- }
- break;
- case 4: { // remap to percent gray
- // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200
- int16 color = argv[1].toSint16();
- int16 percent = argv[2].toSint16(); // 0 - 100
- // argv[3] is unknown (a number, e.g. 200) - start color, perhaps?
- if (argc >= 5)
- warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16());
- g_sci->_gfxPalette32->setRemappingPercentGray(color, percent);
- }
- break;
- case 5: { // don't map to range
- //int16 mapping = argv[1].toSint16();
- uint16 intensity = argv[2].toUint16();
- // HACK for PQ4
- if (g_sci->getGameId() == GID_PQ4)
- g_sci->_gfxPalette32->kernelSetIntensity(0, 255, intensity, true);
-
- kStub(s, argc, argv);
- }
- break;
- default:
- break;
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
+reg_t kRemapColorsOff(EngineState *s, int argc, reg_t *argv) {
+ if (argc == 0) {
+ g_sci->_gfxRemap32->remapAllOff();
+ } else {
+ const uint8 color = argv[0].toUint16();
+ g_sci->_gfxRemap32->remapOff(color);
}
+ return s->r_acc;
+}
+
+reg_t kRemapColorsByRange(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 from = argv[1].toSint16();
+ const int16 to = argv[2].toSint16();
+ const int16 base = argv[3].toSint16();
+ // NOTE: There is an optional last parameter after `base`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapByRange(color, from, to, base);
+ return s->r_acc;
+}
+
+reg_t kRemapColorsByPercent(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 percent = argv[1].toSint16();
+ // NOTE: There is an optional last parameter after `percent`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapByPercent(color, percent);
+ return s->r_acc;
+}
+
+reg_t kRemapColorsToGray(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 gray = argv[1].toSint16();
+ // NOTE: There is an optional last parameter after `gray`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapToGray(color, gray);
+ return s->r_acc;
+}
+
+reg_t kRemapColorsToPercentGray(EngineState *s, int argc, reg_t *argv) {
+ const uint8 color = argv[0].toUint16();
+ const int16 gray = argv[1].toSint16();
+ const int16 percent = argv[2].toSint16();
+ // NOTE: There is an optional last parameter after `percent`
+ // which was only used by the priority map debugger, which
+ // does not exist in release versions of SSCI
+ g_sci->_gfxRemap32->remapToPercentGray(color, gray, percent);
+ return s->r_acc;
+}
+reg_t kRemapColorsBlockRange(EngineState *s, int argc, reg_t *argv) {
+ const uint8 from = argv[0].toUint16();
+ const uint8 count = argv[1].toUint16();
+ g_sci->_gfxRemap32->blockRange(from, count);
return s->r_acc;
}
diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp
index f4bb4ff85b..0d6831139a 100644
--- a/engines/sci/engine/kmisc.cpp
+++ b/engines/sci/engine/kmisc.cpp
@@ -243,10 +243,18 @@ reg_t kGetTime(EngineState *s, int argc, reg_t *argv) {
debugC(kDebugLevelTime, "GetTime(24h) returns %d", retval);
break;
case KGETTIME_DATE :
- // Year since 1980 (0 = 1980, 1 = 1981, etc.)
- retval = loc_time.tm_mday | ((loc_time.tm_mon + 1) << 5) | (((loc_time.tm_year - 80) & 0x7f) << 9);
+ {
+ // SCI0 late: Year since 1920 (0 = 1920, 1 = 1921, etc)
+ // SCI01 and newer: Year since 1980 (0 = 1980, 1 = 1981, etc)
+ // Atari ST SCI0 late versions use the newer base year.
+ int baseYear = 80;
+ if (getSciVersion() == SCI_VERSION_0_LATE && g_sci->getPlatform() == Common::kPlatformDOS) {
+ baseYear = 20;
+ }
+ retval = loc_time.tm_mday | ((loc_time.tm_mon + 1) << 5) | (((loc_time.tm_year - baseYear) & 0x7f) << 9);
debugC(kDebugLevelTime, "GetTime(date) returns %d", retval);
break;
+ }
default:
error("Attempt to use unknown GetTime mode %d", mode);
break;
@@ -401,6 +409,9 @@ reg_t kGetConfig(EngineState *s, int argc, reg_t *argv) {
} else if (setting == "startroom") {
// Debug setting in LSL7, specifies the room to start from.
s->_segMan->strcpy(data, "");
+ } else if (setting == "game") {
+ // Hoyle 5 Demo startup.
+ s->_segMan->strcpy(data, "");
} else {
error("GetConfig: Unknown configuration setting %s", setting.c_str());
}
@@ -597,18 +608,28 @@ reg_t kEmpty(EngineState *s, int argc, reg_t *argv) {
reg_t kStub(EngineState *s, int argc, reg_t *argv) {
Kernel *kernel = g_sci->getKernel();
int kernelCallNr = -1;
+ int kernelSubCallNr = -1;
Common::List<ExecStack>::const_iterator callIterator = s->_executionStack.end();
if (callIterator != s->_executionStack.begin()) {
callIterator--;
ExecStack lastCall = *callIterator;
- kernelCallNr = lastCall.debugSelector;
+ kernelCallNr = lastCall.debugKernelFunction;
+ kernelSubCallNr = lastCall.debugKernelSubFunction;
+ }
+
+ Common::String warningMsg;
+ if (kernelSubCallNr == -1) {
+ warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr) +
+ Common::String::format("[%x]", kernelCallNr);
+ } else {
+ warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr, kernelSubCallNr) +
+ Common::String::format("[%x:%x]", kernelCallNr, kernelSubCallNr);
+
}
- Common::String warningMsg = "Dummy function k" + kernel->getKernelName(kernelCallNr) +
- Common::String::format("[%x]", kernelCallNr) +
- " invoked. Params: " +
- Common::String::format("%d", argc) + " (";
+ warningMsg += " invoked. Params: " +
+ Common::String::format("%d", argc) + " (";
for (int i = 0; i < argc; i++) {
warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 5b2245e84d..06f16299aa 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -326,7 +326,7 @@ static void draw_line(EngineState *s, Common::Point p1, Common::Point p2, int ty
p2.y = CLIP<int16>(p2.y, 0, height - 1);
assert(type >= 0 && type <= 3);
- g_sci->_gfxPaint->kernelGraphDrawLine(p1, p2, poly_colors[type], 255, 255);
+ g_sci->_gfxPaint16->kernelGraphDrawLine(p1, p2, poly_colors[type], 255, 255);
}
static void draw_point(EngineState *s, Common::Point p, int start, int width, int height) {
@@ -1943,14 +1943,14 @@ static int liesBefore(const Vertex *v, const Common::Point &p1, const Common::Po
// indexp1/vertexp1 on the polygon being merged.
// It ends with the point intersection2, being the analogous intersection.
struct Patch {
- unsigned int indexw1;
- unsigned int indexp1;
+ uint32 indexw1;
+ uint32 indexp1;
const Vertex *vertexw1;
const Vertex *vertexp1;
Common::Point intersection1;
- unsigned int indexw2;
- unsigned int indexp2;
+ uint32 indexw2;
+ uint32 indexp2;
const Vertex *vertexw2;
const Vertex *vertexp2;
Common::Point intersection2;
@@ -1960,7 +1960,7 @@ struct Patch {
// Check if the given vertex on the work polygon is bypassed by this patch.
-static bool isVertexCovered(const Patch &p, unsigned int wi) {
+static bool isVertexCovered(const Patch &p, uint32 wi) {
// / v (outside)
// ---w1--1----p----w2--2----
@@ -2402,7 +2402,7 @@ reg_t kMergePoly(EngineState *s, int argc, reg_t *argv) {
// Copy work.vertices into arrayRef
Vertex *vertex;
- unsigned int n = 0;
+ uint32 n = 0;
CLIST_FOREACH(vertex, &work.vertices) {
if (vertex == work.vertices._head || vertex->v != vertex->_prev->v)
writePoint(arrayRef, n++, vertex->v);
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 303de079aa..6fd130bceb 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -260,9 +260,6 @@ reg_t kDisposeScript(EngineState *s, int argc, reg_t *argv) {
if (argc != 2) {
return s->r_acc;
} else {
- // This exists in the KQ5CD and GK1 interpreter. We know it is used
- // when GK1 starts up, before the Sierra logo.
- warning("kDisposeScript called with 2 parameters, still untested");
return argv[1];
}
}
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index 398a623286..ed53b8d52f 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -26,7 +26,11 @@
#include "sci/engine/kernel.h"
#include "sci/engine/vm.h" // for Object
#include "sci/sound/audio.h"
+#ifdef ENABLE_SCI32
+#include "sci/sound/audio32.h"
+#endif
#include "sci/sound/soundcmd.h"
+#include "sci/sound/sync.h"
#include "audio/mixer.h"
#include "common/system.h"
@@ -46,7 +50,6 @@ reg_t kDoSound(EngineState *s, int argc, reg_t *argv) {
CREATE_DOSOUND_FORWARD(DoSoundInit)
CREATE_DOSOUND_FORWARD(DoSoundPlay)
-CREATE_DOSOUND_FORWARD(DoSoundRestore)
CREATE_DOSOUND_FORWARD(DoSoundDispose)
CREATE_DOSOUND_FORWARD(DoSoundMute)
CREATE_DOSOUND_FORWARD(DoSoundStop)
@@ -61,13 +64,41 @@ CREATE_DOSOUND_FORWARD(DoSoundUpdateCues)
CREATE_DOSOUND_FORWARD(DoSoundSendMidi)
CREATE_DOSOUND_FORWARD(DoSoundGlobalReverb)
CREATE_DOSOUND_FORWARD(DoSoundSetHold)
-CREATE_DOSOUND_FORWARD(DoSoundDummy)
CREATE_DOSOUND_FORWARD(DoSoundGetAudioCapability)
CREATE_DOSOUND_FORWARD(DoSoundSuspend)
CREATE_DOSOUND_FORWARD(DoSoundSetVolume)
CREATE_DOSOUND_FORWARD(DoSoundSetPriority)
CREATE_DOSOUND_FORWARD(DoSoundSetLoop)
+#ifdef ENABLE_SCI32
+reg_t kDoSoundPhantasmagoriaMac(EngineState *s, int argc, reg_t *argv) {
+ // Phantasmagoria Mac (and seemingly no other game (!)) uses this
+ // cutdown version of kDoSound.
+
+ switch (argv[0].toUint16()) {
+ case 0:
+ return g_sci->_soundCmd->kDoSoundMasterVolume(argc - 1, argv + 1, s->r_acc);
+ case 2:
+ return g_sci->_soundCmd->kDoSoundInit(argc - 1, argv + 1, s->r_acc);
+ case 3:
+ return g_sci->_soundCmd->kDoSoundDispose(argc - 1, argv + 1, s->r_acc);
+ case 4:
+ return g_sci->_soundCmd->kDoSoundPlay(argc - 1, argv + 1, s->r_acc);
+ case 5:
+ return g_sci->_soundCmd->kDoSoundStop(argc - 1, argv + 1, s->r_acc);
+ case 8:
+ return g_sci->_soundCmd->kDoSoundSetVolume(argc - 1, argv + 1, s->r_acc);
+ case 9:
+ return g_sci->_soundCmd->kDoSoundSetLoop(argc - 1, argv + 1, s->r_acc);
+ case 10:
+ return g_sci->_soundCmd->kDoSoundUpdateCues(argc - 1, argv + 1, s->r_acc);
+ }
+
+ error("Unknown kDoSound Phantasmagoria Mac subop %d", argv[0].toUint16());
+ return s->r_acc;
+}
+#endif
+
reg_t kDoCdAudio(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case kSciAudioPlay: {
@@ -113,7 +144,8 @@ reg_t kDoCdAudio(EngineState *s, int argc, reg_t *argv) {
}
/**
- * Used for speech playback and digital soundtracks in CD games
+ * Used for speech playback and digital soundtracks in CD games.
+ * This is the SCI16 version; SCI32 is handled separately.
*/
reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
// JonesCD uses different functions based on the cdaudio.map file
@@ -184,14 +216,6 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
int16 volume = argv[1].toUint16();
volume = CLIP<int16>(volume, 0, AUDIO_VOLUME_MAX);
debugC(kDebugLevelSound, "kDoAudio: set volume to %d", volume);
-#ifdef ENABLE_SCI32
- if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
- int16 volumePrev = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType) / 2;
- volumePrev = CLIP<int16>(volumePrev, 0, AUDIO_VOLUME_MAX);
- mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2);
- return make_reg(0, volumePrev);
- } else
-#endif
mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume * 2);
break;
}
@@ -232,12 +256,6 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
if (getSciVersion() <= SCI_VERSION_1_1) {
debugC(kDebugLevelSound, "kDoAudio: CD audio subop");
return kDoCdAudio(s, argc - 1, argv + 1);
-#ifdef ENABLE_SCI32
- } else {
- // TODO: This isn't CD Audio in SCI32 anymore
- warning("kDoAudio: Unhandled case 10, %d extra arguments passed", argc - 1);
- break;
-#endif
}
// 3 new subops in Pharkas CD (including CD demo). kDoAudio in Pharkas sits at seg026:038C
@@ -286,14 +304,12 @@ reg_t kDoAudio(EngineState *s, int argc, reg_t *argv) {
}
reg_t kDoSync(EngineState *s, int argc, reg_t *argv) {
- SegManager *segMan = s->_segMan;
switch (argv[0].toUint16()) {
case kSciAudioSyncStart: {
ResourceId id;
- g_sci->_audio->stopSoundSync();
+ g_sci->_sync->stop();
- // Load sound sync resource and lock it
if (argc == 3) {
id = ResourceId(kResourceTypeSync, argv[2].toUint16());
} else if (argc == 7) {
@@ -304,14 +320,14 @@ reg_t kDoSync(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
- g_sci->_audio->setSoundSync(id, argv[1], segMan);
+ g_sci->_sync->start(id, argv[1]);
break;
}
case kSciAudioSyncNext:
- g_sci->_audio->doSoundSync(argv[1], segMan);
+ g_sci->_sync->next(argv[1]);
break;
case kSciAudioSyncStop:
- g_sci->_audio->stopSoundSync();
+ g_sci->_sync->stop();
break;
default:
error("DoSync: Unhandled subfunction %d", argv[0].toUint16());
@@ -321,6 +337,155 @@ reg_t kDoSync(EngineState *s, int argc, reg_t *argv) {
}
#ifdef ENABLE_SCI32
+reg_t kDoAudio32(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
+reg_t kDoAudioInit(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, 0);
+}
+
+reg_t kDoAudioWaitForPlay(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_audio32->kernelPlay(false, argc, argv);
+}
+
+reg_t kDoAudioPlay(EngineState *s, int argc, reg_t *argv) {
+ return g_sci->_audio32->kernelPlay(true, argc, argv);
+}
+
+reg_t kDoAudioStop(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->stop(channelIndex));
+}
+
+reg_t kDoAudioPause(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->pause(channelIndex));
+}
+
+reg_t kDoAudioResume(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->resume(channelIndex));
+}
+
+reg_t kDoAudioPosition(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc > 1 ? argv[1] : NULL_REG);
+ return make_reg(0, g_sci->_audio32->getPosition(channelIndex));
+}
+
+reg_t kDoAudioRate(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would set the hardware
+ // DSP sampling rate; ScummVM mixer does not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ const uint16 sampleRate = argv[0].toUint16();
+ if (sampleRate != 0) {
+ g_sci->_audio32->setSampleRate(sampleRate);
+ }
+ }
+
+ return make_reg(0, g_sci->_audio32->getSampleRate());
+}
+
+reg_t kDoAudioVolume(EngineState *s, int argc, reg_t *argv) {
+ const int16 volume = argc > 0 ? argv[0].toSint16() : -1;
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 1, argc > 2 ? argv[2] : NULL_REG);
+
+ if (volume != -1) {
+ g_sci->_audio32->setVolume(channelIndex, volume);
+ }
+
+ return make_reg(0, g_sci->_audio32->getVolume(channelIndex));
+}
+
+reg_t kDoAudioGetCapability(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, 1);
+}
+
+reg_t kDoAudioBitDepth(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would set the hardware
+ // DSP bit depth; ScummVM mixer does not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ const uint16 bitDepth = argv[0].toUint16();
+ if (bitDepth != 0) {
+ g_sci->_audio32->setBitDepth(bitDepth);
+ }
+ }
+
+ return make_reg(0, g_sci->_audio32->getBitDepth());
+}
+
+reg_t kDoAudioMixing(EngineState *s, int argc, reg_t *argv) {
+ if (argc > 0) {
+ g_sci->_audio32->setAttenuatedMixing(argv[0].toUint16());
+ }
+
+ return make_reg(0, g_sci->_audio32->getAttenuatedMixing());
+}
+
+reg_t kDoAudioChannels(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would set the hardware
+ // DSP stereo output; ScummVM mixer does not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ const int16 numChannels = argv[0].toSint16();
+ if (numChannels != 0) {
+ g_sci->_audio32->setNumOutputChannels(numChannels);
+ }
+ }
+
+ return make_reg(0, g_sci->_audio32->getNumOutputChannels());
+}
+
+reg_t kDoAudioPreload(EngineState *s, int argc, reg_t *argv) {
+ // NOTE: In the original engine this would cause audio
+ // data for new channels to be preloaded to memory when
+ // the channel was initialized; we do not need this, so
+ // we only store the value to satisfy engine compatibility.
+
+ if (argc > 0) {
+ g_sci->_audio32->setPreload(argv[0].toUint16());
+ }
+
+ return make_reg(0, g_sci->_audio32->getPreload());
+}
+
+reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv) {
+ if (argc < 4) {
+ return make_reg(0, 0);
+ }
+
+ // NOTE: Sierra did a nightmarish hack here, temporarily replacing
+ // the argc of the kernel arguments with 2 and then restoring it
+ // after findChannelByArgs was called.
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(2, argv, 0, argc > 5 ? argv[5] : NULL_REG);
+
+ const int16 volume = argv[1].toSint16();
+ const int16 speed = argv[2].toSint16();
+ const int16 steps = argv[3].toSint16();
+ const bool stopAfterFade = argc > 4 ? (bool)argv[4].toUint16() : false;
+
+ return make_reg(0, g_sci->_audio32->fadeChannel(channelIndex, volume, speed, steps, stopAfterFade));
+}
+
+reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, g_sci->_audio32->hasSignal());
+}
+
+reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv) {
+ const int16 channelIndex = g_sci->_audio32->findChannelByArgs(argc, argv, 0, argc == 3 ? argv[2] : NULL_REG);
+
+ const bool loop = argv[0].toSint16() != 0 && argv[0].toSint16() != 1;
+
+ g_sci->_audio32->setLoop(channelIndex, loop);
+ return s->r_acc;
+}
reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv) {
// This is used by script 90 of MUMG Deluxe from the main menu to toggle
@@ -335,33 +500,6 @@ reg_t kSetLanguage(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kDoSoundPhantasmagoriaMac(EngineState *s, int argc, reg_t *argv) {
- // Phantasmagoria Mac (and seemingly no other game (!)) uses this
- // cutdown version of kDoSound.
-
- switch (argv[0].toUint16()) {
- case 0:
- return g_sci->_soundCmd->kDoSoundMasterVolume(argc - 1, argv + 1, s->r_acc);
- case 2:
- return g_sci->_soundCmd->kDoSoundInit(argc - 1, argv + 1, s->r_acc);
- case 3:
- return g_sci->_soundCmd->kDoSoundDispose(argc - 1, argv + 1, s->r_acc);
- case 4:
- return g_sci->_soundCmd->kDoSoundPlay(argc - 1, argv + 1, s->r_acc);
- case 5:
- return g_sci->_soundCmd->kDoSoundStop(argc - 1, argv + 1, s->r_acc);
- case 8:
- return g_sci->_soundCmd->kDoSoundSetVolume(argc - 1, argv + 1, s->r_acc);
- case 9:
- return g_sci->_soundCmd->kDoSoundSetLoop(argc - 1, argv + 1, s->r_acc);
- case 10:
- return g_sci->_soundCmd->kDoSoundUpdateCues(argc - 1, argv + 1, s->r_acc);
- }
-
- error("Unknown kDoSound Phantasmagoria Mac subop %d", argv[0].toUint16());
- return s->r_acc;
-}
-
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index 310e38dbd1..1c08bf597c 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -661,19 +661,6 @@ reg_t kStrSplit(EngineState *s, int argc, reg_t *argv) {
#ifdef ENABLE_SCI32
-reg_t kText(EngineState *s, int argc, reg_t *argv) {
- switch (argv[0].toUint16()) {
- case 0:
- return kTextSize(s, argc - 1, argv + 1);
- default:
- // TODO: Other subops here too, perhaps kTextColors and kTextFonts
- warning("kText(%d)", argv[0].toUint16());
- break;
- }
-
- return s->r_acc;
-}
-
// TODO: there is an unused second argument, happens at least in LSL6 right during the intro
reg_t kStringNew(EngineState *s, int argc, reg_t *argv) {
reg_t stringHandle;
@@ -778,11 +765,14 @@ reg_t kStringCopy(EngineState *s, int argc, reg_t *argv) {
}
// The original engine ignores bad copies too
- if (index2 > string2Size)
+ if (index2 >= string2Size)
return NULL_REG;
// A count of -1 means fill the rest of the array
- uint32 count = argv[4].toSint16() == -1 ? string2Size - index2 + 1 : argv[4].toUint16();
+ uint32 count = string2Size - index2;
+ if (argv[4].toSint16() != -1) {
+ count = MIN(count, (uint32)argv[4].toUint16());
+ }
// reg_t strAddress = argv[0];
SciString *string1 = s->_segMan->lookupString(argv[0]);
diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp
index 8db0c542eb..1096e78cca 100644
--- a/engines/sci/engine/kvideo.cpp
+++ b/engines/sci/engine/kvideo.cpp
@@ -40,7 +40,8 @@
#include "video/qt_decoder.h"
#include "sci/video/seq_decoder.h"
#ifdef ENABLE_SCI32
-#include "video/coktel_decoder.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/video32.h"
#include "sci/video/robot_decoder.h"
#endif
@@ -289,113 +290,73 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
}
reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
- uint16 operation = argv[0].toUint16();
- Video::VideoDecoder *videoDecoder = 0;
- bool reshowCursor = g_sci->_gfxCursor->isVisible();
- Common::String warningMsg;
-
- switch (operation) {
- case 0: // init
- s->_videoState.reset();
- s->_videoState.fileName = s->_segMan->derefString(argv[1]);
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- if (argc > 2 && argv[2] != NULL_REG)
- warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2]));
- break;
- case 1:
- {
- // Set VMD parameters. Called with a maximum of 6 parameters:
- //
- // x, y, flags, gammaBoost, gammaFirst, gammaLast
- //
- // gammaBoost boosts palette colors in the range gammaFirst to
- // gammaLast, but only if bit 4 in flags is set. Percent value such that
- // 0% = no amplification These three parameters are optional if bit 4 is
- // clear. Also note that the x, y parameters play subtle games if used
- // with subfx 21. The subtleness has to do with creation of temporary
- // planes and positioning relative to such planes.
-
- uint16 flags = argv[3].getOffset();
- Common::String flagspec;
-
- if (argc > 3) {
- if (flags & kDoubled)
- flagspec += "doubled ";
- if (flags & kDropFrames)
- flagspec += "dropframes ";
- if (flags & kBlackLines)
- flagspec += "blacklines ";
- if (flags & kUnkBit3)
- flagspec += "bit3 ";
- if (flags & kGammaBoost)
- flagspec += "gammaboost ";
- if (flags & kHoldBlackFrame)
- flagspec += "holdblack ";
- if (flags & kHoldLastFrame)
- flagspec += "holdlast ";
- if (flags & kUnkBit7)
- flagspec += "bit7 ";
- if (flags & kStretch)
- flagspec += "stretch";
-
- warning("VMDFlags: %s", flagspec.c_str());
-
- s->_videoState.flags = flags;
- }
+reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv) {
+ const Common::String fileName = s->_segMan->getString(argv[0]);
+ // argv[1] is an optional cache size argument which we do not use
+ // const uint16 cacheSize = argc > 1 ? CLIP<int16>(argv[1].toSint16(), 16, 1024) : 0;
+ const VMDPlayer::OpenFlags flags = argc > 2 ? (VMDPlayer::OpenFlags)argv[2].toUint16() : VMDPlayer::kOpenFlagNone;
- warning("x, y: %d, %d", argv[1].getOffset(), argv[2].getOffset());
- s->_videoState.x = argv[1].getOffset();
- s->_videoState.y = argv[2].getOffset();
+ return make_reg(0, g_sci->_video32->getVMDPlayer().open(fileName, flags));
+}
- if (argc > 4 && flags & 16)
- warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].getOffset(), argv[5].getOffset(), argv[6].getOffset());
- break;
+reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv) {
+ const int16 x = argv[0].toSint16();
+ const int16 y = argv[1].toSint16();
+ const VMDPlayer::PlayFlags flags = argc > 2 ? (VMDPlayer::PlayFlags)argv[2].toUint16() : VMDPlayer::kPlayFlagNone;
+ int16 boostPercent;
+ int16 boostStartColor;
+ int16 boostEndColor;
+ if (argc > 5 && (flags & VMDPlayer::kPlayFlagBoost)) {
+ boostPercent = argv[3].toSint16();
+ boostStartColor = argv[4].toSint16();
+ boostEndColor = argv[5].toSint16();
+ } else {
+ boostPercent = 0;
+ boostStartColor = -1;
+ boostEndColor = -1;
}
- case 6: // Play
- videoDecoder = new Video::AdvancedVMDDecoder();
- if (s->_videoState.fileName.empty()) {
- // Happens in Lighthouse
- warning("kPlayVMD: Empty filename passed");
- return s->r_acc;
- }
+ g_sci->_video32->getVMDPlayer().init(x, y, flags, boostPercent, boostStartColor, boostEndColor);
- if (!videoDecoder->loadFile(s->_videoState.fileName)) {
- warning("Could not open VMD %s", s->_videoState.fileName.c_str());
- break;
- }
+ return make_reg(0, 0);
+}
- if (reshowCursor)
- g_sci->_gfxCursor->kernelHide();
+reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) {
+ return make_reg(0, g_sci->_video32->getVMDPlayer().close());
+}
- playVideo(videoDecoder, s->_videoState);
+reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv) {
+ const VMDPlayer::EventFlags flags = (VMDPlayer::EventFlags)argv[0].toUint16();
+ const int16 lastFrameNo = argc > 1 ? argv[1].toSint16() : -1;
+ const int16 yieldInterval = argc > 2 ? argv[2].toSint16() : -1;
+ return make_reg(0, g_sci->_video32->getVMDPlayer().kernelPlayUntilEvent(flags, lastFrameNo, yieldInterval));
+}
- if (reshowCursor)
- g_sci->_gfxCursor->kernelShow();
- break;
- case 23: // set video palette range
- s->_vmdPalStart = argv[1].toUint16();
- s->_vmdPalEnd = argv[2].toUint16();
- break;
- case 14:
- // Takes an additional integer parameter (e.g. 3)
- case 16:
- // Takes an additional parameter, usually 0
- case 21:
- // Looks to be setting the video size and position. Called with 4 extra integer
- // parameters (e.g. 86, 41, 235, 106)
- default:
- warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
+reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_video32->getVMDPlayer().setShowCursor((bool)argv[0].toUint16());
+ return s->r_acc;
+}
- for (int i = 0; i < argc; i++) {
- warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
- warningMsg += (i == argc - 1 ? ")" : ", ");
- }
+reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv) {
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
- warning("%s", warningMsg.c_str());
- break;
- }
+ Common::Rect blackoutArea;
+ blackoutArea.left = MAX((int16)0, argv[0].toSint16());
+ blackoutArea.top = MAX((int16)0, argv[1].toSint16());
+ blackoutArea.right = MIN(scriptWidth, (int16)(argv[2].toSint16() + 1));
+ blackoutArea.bottom = MIN(scriptHeight, (int16)(argv[3].toSint16() + 1));
+ g_sci->_video32->getVMDPlayer().setBlackoutArea(blackoutArea);
+ return s->r_acc;
+}
+reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_video32->getVMDPlayer().restrictPalette(argv[0].toUint16(), argv[1].toUint16());
return s->r_acc;
}
diff --git a/engines/sci/engine/object.cpp b/engines/sci/engine/object.cpp
index 0626c084c1..0566d6955f 100644
--- a/engines/sci/engine/object.cpp
+++ b/engines/sci/engine/object.cpp
@@ -255,6 +255,8 @@ void Object::initSelectorsSci3(const byte *buf) {
if (g_sci->getKernel()->getSelectorNamesSize() % 32)
++groups;
+ _mustSetViewVisible.resize(groups);
+
methods = properties = 0;
// Selectors are divided into groups of 32, of which the first
@@ -270,7 +272,9 @@ void Object::initSelectorsSci3(const byte *buf) {
// This object actually has selectors belonging to this group
int typeMask = READ_SCI11ENDIAN_UINT32(seeker);
- for (int bit = 2; bit < 32; ++bit) {
+ _mustSetViewVisible[groupNr] = (typeMask & 1);
+
+ for (int bit = 2; bit < 32; ++bit) {
int value = READ_SCI11ENDIAN_UINT16(seeker + bit * 2);
if (typeMask & (1 << bit)) { // Property
++properties;
@@ -281,7 +285,8 @@ void Object::initSelectorsSci3(const byte *buf) {
}
}
- }
+ } else
+ _mustSetViewVisible[groupNr] = false;
}
_variables.resize(properties);
diff --git a/engines/sci/engine/object.h b/engines/sci/engine/object.h
index cc9f5ebb52..a7be170f4f 100644
--- a/engines/sci/engine/object.h
+++ b/engines/sci/engine/object.h
@@ -262,6 +262,8 @@ public:
bool initBaseObject(SegManager *segMan, reg_t addr, bool doInitSuperClass = true);
void syncBaseObject(const byte *ptr) { _baseObj = ptr; }
+ bool mustSetViewVisibleSci3(int selector) const { return _mustSetViewVisible[selector/32]; }
+
private:
void initSelectorsSci3(const byte *buf);
@@ -278,6 +280,7 @@ private:
reg_t _superClassPosSci3; /**< reg_t pointing to superclass for SCI3 */
reg_t _speciesSelectorSci3; /**< reg_t containing species "selector" for SCI3 */
reg_t _infoSelectorSci3; /**< reg_t containing info "selector" for SCI3 */
+ Common::Array<bool> _mustSetViewVisible; /** cached bit of info to make lookup fast, SCI3 only */
};
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 18cee3321f..31fb848a2c 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -48,8 +48,9 @@
#include "sci/sound/music.h"
#ifdef ENABLE_SCI32
-#include "sci/graphics/palette32.h"
#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
#endif
namespace Sci {
@@ -60,24 +61,125 @@ namespace Sci {
#pragma mark -
-// Experimental hack: Use syncWithSerializer to sync. By default, this assume
-// the object to be synced is a subclass of Serializable and thus tries to invoke
-// the saveLoadWithSerializer() method. But it is possible to specialize this
-// template function to handle stuff that is not implementing that interface.
-template<typename T>
-void syncWithSerializer(Common::Serializer &s, T &obj) {
+// These are serialization functions for various objects.
+
+void syncWithSerializer(Common::Serializer &s, Common::Serializable &obj) {
+ obj.saveLoadWithSerializer(s);
+}
+
+// FIXME: Object could implement Serializable to make use of the function
+// above.
+void syncWithSerializer(Common::Serializer &s, Object &obj) {
obj.saveLoadWithSerializer(s);
}
+void syncWithSerializer(Common::Serializer &s, reg_t &obj) {
+ // Segment and offset are accessed directly here
+ s.syncAsUint16LE(obj._segment);
+ s.syncAsUint16LE(obj._offset);
+}
+
+void syncWithSerializer(Common::Serializer &s, synonym_t &obj) {
+ s.syncAsUint16LE(obj.replaceant);
+ s.syncAsUint16LE(obj.replacement);
+}
+
+void syncWithSerializer(Common::Serializer &s, Class &obj) {
+ s.syncAsSint32LE(obj.script);
+ syncWithSerializer(s, obj.reg);
+}
+
+void syncWithSerializer(Common::Serializer &s, List &obj) {
+ syncWithSerializer(s, obj.first);
+ syncWithSerializer(s, obj.last);
+}
+
+void syncWithSerializer(Common::Serializer &s, Node &obj) {
+ syncWithSerializer(s, obj.pred);
+ syncWithSerializer(s, obj.succ);
+ syncWithSerializer(s, obj.key);
+ syncWithSerializer(s, obj.value);
+}
+
+#ifdef ENABLE_SCI32
+void syncWithSerializer(Common::Serializer &s, SciArray<reg_t> &obj) {
+ byte type = 0;
+ uint32 size = 0;
+
+ if (s.isSaving()) {
+ type = (byte)obj.getType();
+ size = obj.getSize();
+ }
+ s.syncAsByte(type);
+ s.syncAsUint32LE(size);
+ if (s.isLoading()) {
+ obj.setType((int8)type);
+
+ // HACK: Skip arrays that have a negative type
+ if ((int8)type < 0)
+ return;
+
+ obj.setSize(size);
+ }
+
+ for (uint32 i = 0; i < size; i++) {
+ reg_t value;
+
+ if (s.isSaving())
+ value = obj.getValue(i);
+
+ syncWithSerializer(s, value);
+
+ if (s.isLoading())
+ obj.setValue(i, value);
+ }
+}
+
+void syncWithSerializer(Common::Serializer &s, SciString &obj) {
+ uint32 size = 0;
+
+ if (s.isSaving()) {
+ size = obj.getSize();
+ s.syncAsUint32LE(size);
+ } else {
+ s.syncAsUint32LE(size);
+ obj.setSize(size);
+ }
+
+ for (uint32 i = 0; i < size; i++) {
+ char value = 0;
+
+ if (s.isSaving())
+ value = obj.getValue(i);
+
+ s.syncAsByte(value);
+
+ if (s.isLoading())
+ obj.setValue(i, value);
+ }
+}
+#endif
+
+#pragma mark -
+
// By default, sync using syncWithSerializer, which in turn can easily be overloaded.
template<typename T>
struct DefaultSyncer : Common::BinaryFunction<Common::Serializer, T, void> {
void operator()(Common::Serializer &s, T &obj) const {
- //obj.saveLoadWithSerializer(s);
syncWithSerializer(s, obj);
}
};
+// Syncer for entries in a segment obj table
+template<typename T>
+struct SegmentObjTableEntrySyncer : Common::BinaryFunction<Common::Serializer, typename T::Entry &, void> {
+ void operator()(Common::Serializer &s, typename T::Entry &entry) const {
+ s.syncAsSint32LE(entry.next_free);
+
+ syncWithSerializer(s, entry.data);
+ }
+};
+
/**
* Sync a Common::Array using a Common::Serializer.
* When saving, this writes the length of the array, then syncs (writes) all entries.
@@ -116,18 +218,10 @@ void syncArray(Common::Serializer &s, Common::Array<T> &arr) {
sync(s, arr);
}
-
-template<>
-void syncWithSerializer(Common::Serializer &s, reg_t &obj) {
- // Segment and offset are accessed directly here
- s.syncAsUint16LE(obj._segment);
- s.syncAsUint16LE(obj._offset);
-}
-
-template<>
-void syncWithSerializer(Common::Serializer &s, synonym_t &obj) {
- s.syncAsUint16LE(obj.replaceant);
- s.syncAsUint16LE(obj.replacement);
+template<typename T, class Syncer>
+void syncArray(Common::Serializer &s, Common::Array<T> &arr) {
+ ArraySyncer<T, Syncer> sync;
+ sync(s, arr);
}
void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
@@ -247,12 +341,6 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
}
-template<>
-void syncWithSerializer(Common::Serializer &s, Class &obj) {
- s.syncAsSint32LE(obj.script);
- syncWithSerializer(s, obj.reg);
-}
-
static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) {
s.syncString(obj.name);
s.syncVersion(CURRENT_SAVEGAME_VERSION);
@@ -310,8 +398,13 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
_segMan->saveLoadWithSerializer(s);
g_sci->_soundCmd->syncPlayList(s);
- // NOTE: This will be GfxPalette32 for SCI32 engine games
- g_sci->_gfxPalette16->saveLoadWithSerializer(s);
+
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ g_sci->_gfxPalette32->saveLoadWithSerializer(s);
+ } else
+#endif
+ g_sci->_gfxPalette16->saveLoadWithSerializer(s);
}
void Vocabulary::saveLoadWithSerializer(Common::Serializer &s) {
@@ -331,102 +424,13 @@ void Object::saveLoadWithSerializer(Common::Serializer &s) {
syncArray<reg_t>(s, _variables);
}
-template<>
-void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Clone>::Entry &obj) {
- s.syncAsSint32LE(obj.next_free);
-
- syncWithSerializer<Object>(s, obj);
-}
-
-template<>
-void syncWithSerializer(Common::Serializer &s, SegmentObjTable<List>::Entry &obj) {
- s.syncAsSint32LE(obj.next_free);
-
- syncWithSerializer(s, obj.first);
- syncWithSerializer(s, obj.last);
-}
-
-template<>
-void syncWithSerializer(Common::Serializer &s, SegmentObjTable<Node>::Entry &obj) {
- s.syncAsSint32LE(obj.next_free);
-
- syncWithSerializer(s, obj.pred);
- syncWithSerializer(s, obj.succ);
- syncWithSerializer(s, obj.key);
- syncWithSerializer(s, obj.value);
-}
-
-#ifdef ENABLE_SCI32
-template<>
-void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciArray<reg_t> >::Entry &obj) {
- s.syncAsSint32LE(obj.next_free);
-
- byte type = 0;
- uint32 size = 0;
-
- if (s.isSaving()) {
- type = (byte)obj.getType();
- size = obj.getSize();
- }
- s.syncAsByte(type);
- s.syncAsUint32LE(size);
- if (s.isLoading()) {
- obj.setType((int8)type);
-
- // HACK: Skip arrays that have a negative type
- if ((int8)type < 0)
- return;
-
- obj.setSize(size);
- }
-
- for (uint32 i = 0; i < size; i++) {
- reg_t value;
-
- if (s.isSaving())
- value = obj.getValue(i);
-
- syncWithSerializer(s, value);
-
- if (s.isLoading())
- obj.setValue(i, value);
- }
-}
-
-template<>
-void syncWithSerializer(Common::Serializer &s, SegmentObjTable<SciString>::Entry &obj) {
- s.syncAsSint32LE(obj.next_free);
-
- uint32 size = 0;
-
- if (s.isSaving()) {
- size = obj.getSize();
- s.syncAsUint32LE(size);
- } else {
- s.syncAsUint32LE(size);
- obj.setSize(size);
- }
-
- for (uint32 i = 0; i < size; i++) {
- char value = 0;
-
- if (s.isSaving())
- value = obj.getValue(i);
-
- s.syncAsByte(value);
-
- if (s.isLoading())
- obj.setValue(i, value);
- }
-}
-#endif
template<typename T>
void sync_Table(Common::Serializer &s, T &obj) {
s.syncAsSint32LE(obj.first_free);
s.syncAsSint32LE(obj.entries_used);
- syncArray<typename T::Entry>(s, obj._table);
+ syncArray<typename T::Entry, SegmentObjTableEntrySyncer<T> >(s, obj._table);
}
void CloneTable::saveLoadWithSerializer(Common::Serializer &s) {
@@ -768,7 +772,7 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint16LE(_varyFromColor);
s.syncAsSint16LE(_varyToColor);
s.syncAsUint16LE(_varyNumTimesPaused);
- s.syncAsByte(_versionUpdated);
+ s.syncAsByte(_needsUpdate);
s.syncAsSint32LE(_varyTime);
s.syncAsUint32LE(_varyLastTick);
@@ -808,8 +812,33 @@ void GfxPalette32::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsUint16LE(cycler->numTimesPaused);
}
}
+}
+
+void GfxRemap32::saveLoadWithSerializer(Common::Serializer &s) {
+ if (s.getVersion() < 35) {
+ return;
+ }
+
+ s.syncAsByte(_numActiveRemaps);
+ s.syncAsByte(_blockedRangeStart);
+ s.syncAsSint16LE(_blockedRangeCount);
- // TODO: _clutTable
+ for (uint i = 0; i < _remaps.size(); ++i) {
+ SingleRemap &singleRemap = _remaps[i];
+ s.syncAsByte(singleRemap._type);
+ if (s.isLoading() && singleRemap._type != kRemapNone) {
+ singleRemap.reset();
+ }
+ s.syncAsByte(singleRemap._from);
+ s.syncAsByte(singleRemap._to);
+ s.syncAsByte(singleRemap._delta);
+ s.syncAsByte(singleRemap._percent);
+ s.syncAsByte(singleRemap._gray);
+ }
+
+ if (s.isLoading()) {
+ _needsUpdate = true;
+ }
}
#endif
@@ -903,7 +932,7 @@ void SegManager::reconstructClones() {
if (!isUsed)
continue;
- CloneTable::Entry &seeker = ct->_table[j];
+ CloneTable::value_type &seeker = ct->at(j);
const Object *baseObj = getObject(seeker.getSpeciesSelector());
seeker.cloneFromObject(baseObj);
if (!baseObj) {
@@ -1012,6 +1041,26 @@ void gamestate_afterRestoreFixUp(EngineState *s, int savegameId) {
g_sci->_gfxMenu->kernelSetAttribute(1025 >> 8, 1025 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Status -> Statistics
g_sci->_gfxMenu->kernelSetAttribute(1026 >> 8, 1026 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, TRUE_REG); // Status -> Goals
break;
+ case GID_KQ6:
+ if (g_sci->isCD()) {
+ // WORKAROUND:
+ // For the CD version of King's Quest 6, set global depending on current hires/lowres state
+ // The game sets a global at the start depending on it and some things check that global
+ // instead of checking platform like for example the game action menu.
+ // This never happened in the original interpreter, because the original DOS interpreter
+ // was only capable of lowres graphics and the original Windows 3.11 interpreter was only capable
+ // of hires graphics. Saved games were not compatible between those two.
+ // Which means saving during lowres mode, then going into hires mode and restoring that saved game,
+ // will result in some graphics being incorrect (lowres).
+ // That's why we are setting the global after restoring a saved game depending on hires/lowres state.
+ // The CD demo of KQ6 does the same and uses the exact same global.
+ if ((g_sci->getPlatform() == Common::kPlatformWindows) || (g_sci->forceHiresGraphics())) {
+ s->variables[VAR_GLOBAL][0xA9].setOffset(1);
+ } else {
+ s->variables[VAR_GLOBAL][0xA9].setOffset(0);
+ }
+ }
+ break;
case GID_PQ2:
// HACK: Same as above - enable the save game menu option when loading in PQ2 (bug #6875).
// It gets disabled in the game's death screen.
@@ -1081,8 +1130,13 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
// We MUST NOT delete all planes/screen items. At least Space Quest 6 has a few in memory like for example
// the options plane, which are not re-added and are in memory all the time right from the start of the
// game. Sierra SCI32 did not clear planes, only scripts cleared the ones inside planes::elements.
- if (getSciVersion() >= SCI_VERSION_2)
- g_sci->_gfxFrameout->syncWithScripts(false);
+ if (getSciVersion() >= SCI_VERSION_2) {
+ if (!s->_delayedRestoreFromLauncher) {
+ // Only do it, when we are restoring regulary and not from launcher
+ // As it could result in option planes etc. on the screen (happens in gk1)
+ g_sci->_gfxFrameout->syncWithScripts(false);
+ }
+ }
#endif
s->reset(true);
@@ -1131,6 +1185,8 @@ void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
// signal restored game to game scripts
s->gameIsRestarting = GAMEISRESTARTING_RESTORE;
+
+ s->_delayedRestoreFromLauncher = false;
}
bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) {
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 459e992e24..43909accf2 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -37,6 +37,7 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
+ * 35 - SCI32 remap
* 34 - SCI32 palettes, and store play time in ticks
* 33 - new overridePriority flag in MusicEntry
* 32 - new playBed flag in MusicEntry
@@ -59,7 +60,7 @@ struct EngineState;
*/
enum {
- CURRENT_SAVEGAME_VERSION = 34,
+ CURRENT_SAVEGAME_VERSION = 35,
MINIMUM_SAVEGAME_VERSION = 14
};
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index fc0dca5123..e6eed0b4b7 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -379,12 +379,40 @@ static const SciScriptPatcherEntry ecoquest2Signatures[] = {
};
// ===========================================================================
+// Fan-made games
+// Attention: Try to make script patches as specific as possible
+
+// CascadeQuest::autosave in script 994 is called various times to auto-save the game.
+// The script use a fixed slot "999" for this purpose. This doesn't work in ScummVM, because we do not let
+// scripts save directly into specific slots, but instead use virtual slots / detect scripts wanting to
+// create a new slot.
+//
+// For this game we patch the code to use slot 99 instead. kSaveGame also checks for Cascade Quest,
+// will then check, if slot 99 is asked for and will then use the actual slot 0, which is the official
+// ScummVM auto-save slot.
+//
+// Responsible method: CascadeQuest::autosave
+// Fixes bug: #7007
+static const uint16 fanmadeSignatureCascadeQuestFixAutoSaving[] = {
+ SIG_MAGICDWORD,
+ 0x38, SIG_UINT16(0x03e7), // pushi 3E7 (999d) -> save game slot 999
+ 0x74, SIG_UINT16(0x06f8), // lofss "AutoSave"
+ 0x89, 0x1e, // lsg global[1E]
+ 0x43, 0x2d, 0x08, // callk SaveGame
+ SIG_END
+};
+
+static const uint16 fanmadePatchCascadeQuestFixAutoSaving[] = {
+ 0x38, PATCH_UINT16((SAVEGAMEID_OFFICIALRANGE_START - 1)), // fix slot
+ PATCH_END
+};
+
// EventHandler::handleEvent in Demo Quest has a bug, and it jumps to the
// wrong address when an incorrect word is typed, therefore leading to an
// infinite loop. This script bug was not apparent in SSCI, probably because
// event handling was slightly different there, so it was never discovered.
// Fixes bug: #5120
-static const uint16 fanmadeSignatureInfiniteLoop[] = {
+static const uint16 fanmadeSignatureDemoQuestInfiniteLoop[] = {
0x38, SIG_UINT16(0x004c), // pushi 004c
0x39, 0x00, // pushi 00
0x87, 0x01, // lap 01
@@ -395,15 +423,16 @@ static const uint16 fanmadeSignatureInfiniteLoop[] = {
SIG_END
};
-static const uint16 fanmadePatchInfiniteLoop[] = {
+static const uint16 fanmadePatchDemoQuestInfiniteLoop[] = {
PATCH_ADDTOOFFSET(+10),
- 0x30, SIG_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c
+ 0x30, PATCH_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c
PATCH_END
};
-// script, description, signature patch
+// script, description, signature patch
static const SciScriptPatcherEntry fanmadeSignatures[] = {
- { true, 999, "infinite loop on typo", 1, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop },
+ { true, 994, "Cascade Quest: fix auto-saving", 1, fanmadeSignatureCascadeQuestFixAutoSaving, fanmadePatchCascadeQuestFixAutoSaving },
+ { true, 999, "Demo Quest: infinite loop on typo", 1, fanmadeSignatureDemoQuestInfiniteLoop, fanmadePatchDemoQuestInfiniteLoop },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -813,6 +842,32 @@ static const uint16 kq5PatchWitchCageInit[] = {
PATCH_END
};
+// The multilingual releases of KQ5 hang right at the end during the magic battle with Mordack.
+// It seems additional code was added to wait for signals, but the signals are never set and thus
+// the game hangs. We disable that code, so that the battle works again.
+// This also happened in the original interpreter.
+// We must not change similar code, that happens before.
+
+// Applies to at least: French PC floppy, German PC floppy, Spanish PC floppy
+// Responsible method: stingScript::changeState, dragonScript::changeState, snakeScript::changeState
+static const uint16 kq5SignatureMultilingualEndingGlitch[] = {
+ SIG_MAGICDWORD,
+ 0x89, 0x57, // lsg global[57h]
+ 0x35, 0x00, // ldi 0
+ 0x1a, // eq?
+ 0x18, // not
+ 0x30, SIG_UINT16(0x0011), // bnt [skip signal check]
+ SIG_ADDTOOFFSET(+8), // skip globalSound::prevSignal get code
+ 0x36, // push
+ 0x35, 0x0a, // ldi 0Ah
+ SIG_END
+};
+
+static const uint16 kq5PatchMultilingualEndingGlitch[] = {
+ PATCH_ADDTOOFFSET(+6),
+ 0x32, // change BNT into JMP
+ PATCH_END
+};
// In the final battle, the DOS version uses signals in the music to handle
// timing, while in the Windows version another method is used and the GM
@@ -843,9 +898,10 @@ static const uint16 kq5PatchWinGMSignals[] = {
// script, description, signature patch
static const SciScriptPatcherEntry kq5Signatures[] = {
- { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
- { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
- { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals },
+ { true, 0, "CD: harpy volume change", 1, kq5SignatureCdHarpyVolume, kq5PatchCdHarpyVolume },
+ { true, 200, "CD: witch cage init", 1, kq5SignatureWitchCageInit, kq5PatchWitchCageInit },
+ { true, 124, "Multilingual: Ending glitching out", 3, kq5SignatureMultilingualEndingGlitch, kq5PatchMultilingualEndingGlitch },
+ { false, 124, "Win: GM Music signal checks", 4, kq5SignatureWinGMSignals, kq5PatchWinGMSignals },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1397,6 +1453,167 @@ static const SciScriptPatcherEntry kq6Signatures[] = {
};
// ===========================================================================
+
+// King's Quest 7 has really weird subtitles. It seems as if the subtitles were
+// not fully finished.
+//
+// Method kqMessager::findTalker in script 0 tries to figure out, which class to use for
+// displaying subtitles. It uses the "talker" data of the given message to do that.
+// Strangely this "talker" data seems to be quite broken.
+// For example chapter 2 starts with a cutscene.
+// Troll king: "Welcome, most beautiful of princesses!" - talker 6
+// Which is followed by the princess going
+// "Hmm?" - which is set to talker 99, normally the princess is talker 7.
+//
+// Talker 99 is seen as unknown and thus treated as "narrator", which makes
+// the scripts put the text at the top of the game screen and even use a
+// different font.
+//
+// In other cases, when the player character thinks to himself talker 99
+// is also used. In such situations it may make somewhat sense to do so,
+// but putting the text at the top of the screen is also irritating to the player.
+// It's really weird.
+//
+// The scripts also put the regular text in the middle of the screen, blocking
+// animations.
+//
+// And for certain rooms, the subtitle box may use another color
+// like for example pink/purple at the start of chapter 5.
+//
+// We fix all of that (hopefully - lots of testing is required).
+// We put the text at the bottom of the play screen.
+// We also make the scripts use the regular KQTalker instead of KQNarrator.
+// And we also make the subtitle box use color 255, which is fixed white.
+//
+// Applies to at least: PC CD 1.4 English, 1.51 English, 1.51 German, 2.00 English
+// Patched method: KQNarrator::init (script 31)
+static const uint16 kq7SignatureSubtitleFix1[] = {
+ SIG_MAGICDWORD,
+ 0x39, 0x25, // pushi 25h (fore)
+ 0x78, // push1
+ 0x39, 0x06, // pushi 06 - sets back to 6
+ 0x39, 0x26, // pushi 26 (back)
+ 0x78, // push1
+ 0x78, // push1 - sets back to 1
+ 0x39, 0x2a, // pushi 2Ah (font)
+ 0x78, // push1
+ 0x89, 0x16, // lsg global[16h] - sets font to global[16h]
+ 0x7a, // push2 (y)
+ 0x78, // push1
+ 0x76, // push0 - sets y to 0
+ 0x54, SIG_UINT16(0x0018), // self 18h
+ SIG_END
+};
+
+static const uint16 kq7PatchSubtitleFix1[] = {
+ 0x33, 0x12, // jmp [skip special init code]
+ PATCH_END
+};
+
+// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
+// Patched method: Narrator::init (script 64928)
+static const uint16 kq7SignatureSubtitleFix2[] = {
+ SIG_MAGICDWORD,
+ 0x89, 0x5a, // lsg global[5a]
+ 0x35, 0x02, // ldi 02
+ 0x12, // and
+ 0x31, 0x1e, // bnt [skip audio volume code]
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
+ 0x76, // push0
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x04, 0x00, // send 04
+ 0x65, 0x32, // aTop curVolume
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi masterVolume (0212h for 2.00, 0219h for 1.51)
+ 0x78, // push1
+ 0x67, 0x32, // pTos curVolume
+ 0x35, 0x02, // ldi 02
+ 0x06, // mul
+ 0x36, // push
+ 0x35, 0x03, // ldi 03
+ 0x08, // div
+ 0x36, // push
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x06, 0x00, // send 06
+ // end of volume code
+ 0x35, 0x01, // ldi 01
+ 0x65, 0x28, // aTop initialized
+ SIG_END
+};
+
+static const uint16 kq7PatchSubtitleFix2[] = {
+ PATCH_ADDTOOFFSET(+5), // skip to bnt
+ 0x31, 0x1b, // bnt [skip audio volume code]
+ PATCH_ADDTOOFFSET(+15), // right after "aTop curVolume / pushi masterVolume / push1"
+ 0x7a, // push2
+ 0x06, // mul (saves 3 bytes in total)
+ 0x36, // push
+ 0x35, 0x03, // ldi 03
+ 0x08, // div
+ 0x36, // push
+ 0x81, 0x01, // lag global[1]
+ 0x4a, 0x06, 0x00, // send 06
+ // end of volume code
+ 0x35, 118, // ldi 118d
+ 0x65, 0x16, // aTop y
+ 0x78, // push1 (saves 1 byte)
+ 0x69, 0x28, // sTop initialized
+ PATCH_END
+};
+
+// Applies to at least: PC CD 1.51 English, 1.51 German, 2.00 English
+// Patched method: Narrator::say (script 64928)
+static const uint16 kq7SignatureSubtitleFix3[] = {
+ SIG_MAGICDWORD,
+ 0x63, 0x28, // pToa initialized
+ 0x18, // not
+ 0x31, 0x07, // bnt [skip init code]
+ 0x38, SIG_ADDTOOFFSET(+2), // pushi init (008Eh for 2.00, 0093h for 1.51)
+ 0x76, // push0
+ 0x54, SIG_UINT16(0x0004), // self 04
+ // end of init code
+ 0x8f, 0x00, // lsp param[0]
+ 0x35, 0x01, // ldi 01
+ 0x1e, // gt?
+ 0x31, 0x08, // bnt [set acc to 0]
+ 0x87, 0x02, // lap param[2]
+ 0x31, 0x04, // bnt [set acc to 0]
+ 0x87, 0x02, // lap param[2]
+ 0x33, 0x02, // jmp [over set acc to 0 code]
+ 0x35, 0x00, // ldi 00
+ 0x65, 0x18, // aTop caller
+ SIG_END
+};
+
+static const uint16 kq7PatchSubtitleFix3[] = {
+ PATCH_ADDTOOFFSET(+2), // skip over "pToa initialized code"
+ 0x2f, 0x0c, // bt [skip init code] - saved 1 byte
+ 0x38,
+ PATCH_GETORIGINALBYTE(+6),
+ PATCH_GETORIGINALBYTE(+7), // pushi (init)
+ 0x76, // push0
+ 0x54, PATCH_UINT16(0x0004), // self 04
+ // additionally set background color here (5 bytes)
+ 0x34, PATCH_UINT16(255), // pushi 255d
+ 0x65, 0x2e, // aTop back
+ // end of init code
+ 0x8f, 0x00, // lsp param[0]
+ 0x35, 0x01, // ldi 01 - this may get optimized to get another byte
+ 0x1e, // gt?
+ 0x31, 0x04, // bnt [set acc to 0]
+ 0x87, 0x02, // lap param[2]
+ 0x2f, 0x02, // bt [over set acc to 0 code]
+ PATCH_END
+};
+
+// script, description, signature patch
+static const SciScriptPatcherEntry kq7Signatures[] = {
+ { true, 31, "subtitle fix 1/3", 1, kq7SignatureSubtitleFix1, kq7PatchSubtitleFix1 },
+ { true, 64928, "subtitle fix 2/3", 1, kq7SignatureSubtitleFix2, kq7PatchSubtitleFix2 },
+ { true, 64928, "subtitle fix 3/3", 1, kq7SignatureSubtitleFix3, kq7PatchSubtitleFix3 },
+ SCI_SIGNATUREENTRY_TERMINATOR
+};
+
+// ===========================================================================
// Script 210 in the German version of Longbow handles the case where Robin
// hands out the scroll to Marion and then types his name using the hand code.
// The German version script contains a typo (probably a copy/paste error),
@@ -1436,9 +1653,109 @@ static const uint16 longbowPatchShowHandCode[] = {
PATCH_END
};
+// When walking through the forest, arithmetic errors may occur at "random".
+// The scripts try to add a value and a pointer to the object "berryBush".
+//
+// This is caused by a local variable overflow.
+//
+// The scripts create berry bush objects dynamically. The array storage for
+// those bushes may hold a total of 8 bushes. But sometimes 10 bushes
+// are created. This overwrites 2 additional locals in script 225 and
+// those locals are used normally for value lookups.
+//
+// Changing the total of bushes could cause all sorts of other issues,
+// that's why I rather patched the code, that uses the locals for a lookup.
+// Which means it doesn't matter anymore when those locals are overwritten.
+//
+// Applies to at least: English PC floppy, German PC floppy, English Amiga floppy
+// Responsible method: export 2 of script 225
+// Fixes bug: #6751
+static const uint16 longbowSignatureBerryBushFix[] = {
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x03, // ldi 03h
+ 0x1a, // eq?
+ 0x2e, SIG_UINT16(0x002d), // bt [process code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x04, // ldi 04h
+ 0x1a, // eq?
+ 0x2e, SIG_UINT16(0x0025), // bt [process code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x05, // ldi 05h
+ 0x1a, // eq?
+ 0x2e, SIG_UINT16(0x001d), // bt [process code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x06, // ldi 06h
+ 0x1a, // eq?
+ 0x2e, SIG_UINT16(0x0015), // bt [process code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x18, // ldi 18h
+ 0x1a, // eq?
+ 0x2e, SIG_UINT16(0x000d), // bt [process code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x19, // ldi 19h
+ 0x1a, // eq?
+ 0x2e, SIG_UINT16(0x0005), // bt [process code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x1a, // ldi 1Ah
+ 0x1a, // eq?
+ // jump location for the "bt" instructions
+ 0x30, SIG_UINT16(0x0011), // bnt [skip over follow up code, to offset 0c35]
+ // 55 bytes until here
+ 0x85, 00, // lat temp[0]
+ SIG_MAGICDWORD,
+ 0x9a, SIG_UINT16(0x0110), // lsli local[110h] -> 110h points normally to 110h / 2Bh
+ // 5 bytes
+ 0x7a, // push2
+ SIG_END
+};
+
+static const uint16 longbowPatchBerryBushFix[] = {
+ PATCH_ADDTOOFFSET(+4), // keep: lsg global[70h], ldi 03h
+ 0x22, // lt? (global < 03h)
+ 0x2f, 0x42, // bt [skip over all the code directly]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x06, // ldi 06h
+ 0x24, // le? (global <= 06h)
+ 0x2f, 0x0e, // bt [to kRandom code]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x18, // ldi 18h
+ 0x22, // lt? (global < 18h)
+ 0x2f, 0x34, // bt [skip over all the code directly]
+ 0x89, 0x70, // lsg global[70h]
+ 0x35, 0x1a, // ldi 1Ah
+ 0x24, // le? (global <= 1Ah)
+ 0x31, 0x2d, // bnt [skip over all the code directly]
+ // 28 bytes, 27 bytes saved
+ // kRandom code
+ 0x85, 0x00, // lat temp[0]
+ 0x2f, 0x05, // bt [skip over case 0]
+ // temp[0] == 0
+ 0x38, SIG_UINT16(0x0110), // pushi 0110h - that's what's normally at local[110h]
+ 0x33, 0x18, // jmp [kRandom call]
+ // check temp[0] further
+ 0x78, // push1
+ 0x1a, // eq?
+ 0x31, 0x05, // bt [skip over case 1]
+ // temp[0] == 1
+ 0x38, SIG_UINT16(0x002b), // pushi 002Bh - that's what's normally at local[111h]
+ 0x33, 0x0F, // jmp [kRandom call]
+ // temp[0] >= 2
+ 0x8d, 00, // lst temp[0]
+ 0x35, 0x02, // ldi 02
+ 0x04, // sub
+ 0x9a, SIG_UINT16(0x0112), // lsli local[112h] -> look up value in 2nd table
+ // this may not be needed at all and was just added for safety reasons
+ // waste 9 spare bytes
+ 0x35, 0x00, // ldi 00
+ 0x35, 0x00, // ldi 00
+ 0x34, PATCH_UINT16(0x0000), // ldi 0000
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry longbowSignatures[] = {
{ true, 210, "hand code crash", 5, longbowSignatureShowHandCode, longbowPatchShowHandCode },
+ { true, 225, "arithmetic berry bush fix", 1, longbowSignatureBerryBushFix, longbowPatchBerryBushFix },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -1627,9 +1944,160 @@ static const uint16 laurabow1PatchEasterEggViewFix[] = {
PATCH_END
};
+// When oiling the armor or opening the visor of the armor, the scripts
+// first check if Laura/ego is near the armor and if she is not, they will move her
+// to the armor. After that further code is executed.
+//
+// The current location is checked by a ego::inRect() call.
+//
+// The given rect for the inRect call inside openVisor::changeState was made larger for Atari ST/Amiga versions.
+// We change the PC version to use the same rect.
+//
+// Additionally the coordinate, that Laura is moved to, is 152, 107 and may not be reachable depending on where
+// Laura/ego was, when "use oil on helmet of armor" / "open visor of armor" got entered.
+// Bad coordinates are for example 82, 110, which then cause collisions and effectively an endless loop.
+// Game will effectively "freeze" and the user is only able to restore a previous game.
+// This also happened, when using the original interpreter.
+// We change the destination coordinate to 152, 110, which seems to be reachable all the time.
+//
+// The following patch fixes the rect for the PC version of the game.
+//
+// Applies to at least: English PC Floppy
+// Responsible method: openVisor::changeState (script 37)
+// Fixes bug: #7119
+static const uint16 laurabow1SignatureArmorOpenVisorFix[] = {
+ 0x39, 0x04, // pushi 04
+ SIG_MAGICDWORD,
+ 0x39, 0x6a, // pushi 6a (106d)
+ 0x38, SIG_UINT16(0x96), // pushi 0096 (150d)
+ 0x39, 0x6c, // pushi 6c (108d)
+ 0x38, SIG_UINT16(0x98), // pushi 0098 (152d)
+ SIG_END
+};
+
+static const uint16 laurabow1PatchArmorOpenVisorFix[] = {
+ PATCH_ADDTOOFFSET(+2),
+ 0x39, 0x68, // pushi 68 (104d) (-2)
+ 0x38, SIG_UINT16(0x94), // pushi 0094 (148d) (-2)
+ 0x39, 0x6f, // pushi 6f (111d) (+3)
+ 0x38, SIG_UINT16(0x9a), // pushi 009a (154d) (+2)
+ PATCH_END
+};
+
+// This here fixes the destination coordinate (exact details are above).
+//
+// Applies to at least: English PC Floppy, English Atari ST Floppy, English Amiga Floppy
+// Responsible method: openVisor::changeState, oiling::changeState (script 37)
+// Fixes bug: #7119
+static const uint16 laurabow1SignatureArmorMoveToFix[] = {
+ SIG_MAGICDWORD,
+ 0x36, // push
+ 0x39, 0x6b, // pushi 6B (107d)
+ 0x38, SIG_UINT16(0x0098), // pushi 98 (152d)
+ 0x7c, // pushSelf
+ 0x81, 0x00, // lag global[0]
+ SIG_END
+};
+
+static const uint16 laurabow1PatchArmorMoveToFix[] = {
+ PATCH_ADDTOOFFSET(+1),
+ 0x39, 0x6e, // pushi 6E (110d) - adjust x, so that no collision can occur anymore
+ PATCH_END
+};
+
+// In some cases like for example when the player oils the arm of the armor, command input stays
+// disabled, even when the player exits fast enough, so that Laura doesn't die.
+//
+// This is caused by the scripts only enabling control (directional movement), but do not enable command input as well.
+//
+// This bug also happens, when using the original interpreter.
+// And it was fixed for the Atari ST + Amiga versions of the game.
+//
+// Applies to at least: English PC Floppy
+// Responsible method: 2nd subroutine in script 37, called by oiling::changeState(7)
+// Fixes bug: #7154
+static const uint16 laurabow1SignatureArmorOilingArmFix[] = {
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ SIG_MAGICDWORD,
+ 0x72, SIG_UINT16(0x1a5c), // lofsa "Can" - offsets are not skipped to make sure only the PC version gets patched
+ 0x4a, 0x04, // send 04
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x19a1), // lofsa "Visor"
+ 0x4a, 0x04, // send 04
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x194a), // lofsa "note"
+ 0x4a, 0x04, // send 04
+ 0x38, SIG_UINT16(0x0089), // pushi 89h
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x18f3), // lofsa "valve"
+ 0x4a, 0x04, // send 04
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x02, // ldi 02
+ 0x1c, // ne?
+ 0x30, SIG_UINT16(0x0014), // bnt [to ret]
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x05, // ldi 05
+ 0x1c, // ne?
+ 0x30, SIG_UINT16(0x000c), // bnt [to ret]
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x06, // ldi 06
+ 0x1c, // ne?
+ 0x30, SIG_UINT16(0x0004), // bnt [to ret]
+ // followed by code to call script 0 export to re-enable controls and call setMotion
+ SIG_END
+};
+
+static const uint16 laurabow1PatchArmorOilingArmFix[] = {
+ PATCH_ADDTOOFFSET(+3), // skip over pushi 89h
+ 0x3c, // dup
+ 0x3c, // dup
+ 0x3c, // dup
+ // saves a total of 6 bytes
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x1a59), // lofsa "Can"
+ 0x4a, 0x04, // send 04
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x19a1), // lofsa "Visor"
+ 0x4a, 0x04, // send 04
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x194d), // lofsa "note"
+ 0x4a, 0x04, // send 04
+ 0x76, // push0
+ 0x72, SIG_UINT16(0x18f9), // lofsa "valve" 18f3
+ 0x4a, 0x04, // send 04
+ // new code to enable input as well, needs 9 spare bytes
+ 0x38, SIG_UINT16(0x00e2), // canInput
+ 0x78, // push1
+ 0x78, // push1
+ 0x51, 0x2b, // class User
+ 0x4a, 0x06, // send 06 -> call User::canInput(1)
+ // original code, but changed a bit to save some more bytes
+ 0x8b, 0x34, // lsl local[34h]
+ 0x35, 0x02, // ldi 02
+ 0x04, // sub
+ 0x31, 0x12, // bnt [to ret]
+ 0x36, // push
+ 0x35, 0x03, // ldi 03
+ 0x04, // sub
+ 0x31, 0x0c, // bnt [to ret]
+ 0x78, // push1
+ 0x1a, // eq?
+ 0x2f, 0x08, // bt [to ret]
+ // saves 7 bytes, we only need 3, so waste 4 bytes
+ 0x35, 0x00, // ldi 0
+ 0x35, 0x00, // ldi 0
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry laurabow1Signatures[] = {
- { true, 4, "easter egg view fix", 1, laurabow1SignatureEasterEggViewFix, laurabow1PatchEasterEggViewFix },
+ { true, 4, "easter egg view fix", 1, laurabow1SignatureEasterEggViewFix, laurabow1PatchEasterEggViewFix },
+ { true, 37, "armor open visor fix", 1, laurabow1SignatureArmorOpenVisorFix, laurabow1PatchArmorOpenVisorFix },
+ { true, 37, "armor move to fix", 2, laurabow1SignatureArmorMoveToFix, laurabow1PatchArmorMoveToFix },
+ { true, 37, "allowing input, after oiling arm", 1, laurabow1SignatureArmorOilingArmFix, laurabow1PatchArmorOilingArmFix },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -2734,7 +3202,7 @@ static const uint16 qfg3PatchImportDialog[] = {
// Teller::doChild. We jump to this call of hero::solvePuzzle to get that same
// behaviour.
// Applies to at least: English, German, Italian, French, Spanish Floppy
-// Responsible method: unknown
+// Responsible method: uhuraTell::doChild
// Fixes bug: #5172
static const uint16 qfg3SignatureWooDialog[] = {
SIG_MAGICDWORD,
@@ -2907,6 +3375,84 @@ static const uint16 qfg3PatchChiefPriority[] = {
PATCH_END
};
+// There are 3 points that can't be achieved in the game. They should've been
+// awarded for telling Rakeesh and Kreesha (room 285) about the Simabni
+// initiation.
+// However the array of posibble messages the hero can tell in that room
+// (local 156) is missing the "Tell about Initiation" message (#31) which
+// awards these points.
+// This patch adds the message to that array, thus allowing the hero to tell
+// that message (after completing the initiation) and gain the 3 points.
+// A side effect of increasing the local156 array is that the next local
+// array is shifted and shrinks in size from 4 words to 3. The patch changes
+// the 2 locations in the script that reference that array, to point to the new
+// location ($aa --> $ab). It is safe to shrink the 2nd array to 3 words
+// because only the first element in it is ever used.
+//
+// Note: You have to re-enter the room in case a saved game was loaded from a
+// previous version of ScummVM and that saved game was made inside that room.
+//
+// Applies to: English, French, German, Italian, Spanish and the GOG release.
+// Responsible method: heap in script 285
+// Fixes bug #7086
+static const uint16 qfg3SignatureMissingPoints1[] = {
+ // local[$9c] = [0 -41 -76 1 -30 -77 -33 -34 -35 -36 -37 -42 -80 999]
+ // local[$aa] = [0 0 0 0]
+ SIG_UINT16(0x0000), // 0 START MARKER
+ SIG_MAGICDWORD,
+ SIG_UINT16(0xFFD7), // -41 "Greet"
+ SIG_UINT16(0xFFB4), // -76 "Say Good-bye"
+ SIG_UINT16(0x0001), // 1 "Tell about Tarna"
+ SIG_UINT16(0xFFE2), // -30 "Tell about Simani"
+ SIG_UINT16(0xFFB3), // -77 "Tell about Prisoner"
+ SIG_UINT16(0xFFDF), // -33 "Dispelled Leopard Lady"
+ SIG_UINT16(0xFFDE), // -34 "Tell about Leopard Lady"
+ SIG_UINT16(0xFFDD), // -35 "Tell about Leopard Lady"
+ SIG_UINT16(0xFFDC), // -36 "Tell about Leopard Lady"
+ SIG_UINT16(0xFFDB), // -37 "Tell about Village"
+ SIG_UINT16(0xFFD6), // -42 "Greet"
+ SIG_UINT16(0xFFB0), // -80 "Say Good-bye"
+ SIG_UINT16(0x03E7), // 999 END MARKER
+ SIG_ADDTOOFFSET(+2), // local[$aa][0]
+ SIG_END
+};
+
+static const uint16 qfg3PatchMissingPoints1[] = {
+ PATCH_ADDTOOFFSET(+14),
+ PATCH_UINT16(0xFFE1), // -31 "Tell about Initiation"
+ PATCH_UINT16(0xFFDE), // -34 "Tell about Leopard Lady"
+ PATCH_UINT16(0xFFDD), // -35 "Tell about Leopard Lady"
+ PATCH_UINT16(0xFFDC), // -36 "Tell about Leopard Lady"
+ PATCH_UINT16(0xFFDB), // -37 "Tell about Village"
+ PATCH_UINT16(0xFFD6), // -42 "Greet"
+ PATCH_UINT16(0xFFB0), // -80 "Say Good-bye"
+ PATCH_UINT16(0x03E7), // 999 END MARKER
+ PATCH_GETORIGINALBYTE(+28), // local[$aa][0].low
+ PATCH_GETORIGINALBYTE(+29), // local[$aa][0].high
+ PATCH_END
+};
+
+static const uint16 qfg3SignatureMissingPoints2a[] = {
+ SIG_MAGICDWORD,
+ 0x35, 0x00, // ldi 0
+ 0xb3, 0xaa, // sali local[$aa]
+ SIG_END
+};
+
+static const uint16 qfg3SignatureMissingPoints2b[] = {
+ SIG_MAGICDWORD,
+ 0x36, // push
+ 0x5b, 0x02, 0xaa, // lea local[$aa]
+ SIG_END
+};
+
+static const uint16 qfg3PatchMissingPoints2[] = {
+ PATCH_ADDTOOFFSET(+3),
+ 0xab, // local[$aa] ==> local[$ab]
+ PATCH_END
+};
+
+
// Partly WORKAROUND:
// During combat, the game is not properly throttled. That's because the game uses
// an inner loop for combat and does not iterate through the main loop.
@@ -2966,16 +3512,102 @@ static const uint16 qfg3PatchCombatSpeedThrottling2[] = {
PATCH_END
};
+// In room #750, when the hero enters from the top east path (room #755), it
+// could go out of the contained-access polygon bounds, and be able to travel
+// freely in the room.
+// The reason is that the cutoff y value (42) that determines whether the hero
+// enters from the top or bottom path is inaccurate: it's possible to enter the
+// top path from as low as y=45.
+// This patch changes the cutoff to be 50 which should be low enough.
+// It also changes the position in which the hero enters from the top east path
+// as the current location is hidden behind the tree.
+//
+// Applies to: English, French, German, Italian, Spanish and the GOG release.
+// Responsible method: enterEast::changeState (script 750)
+// Fixes bug #6693
+static const uint16 qfg3SignatureRoom750Bounds1[] = {
+ // (if (< (ego y?) 42)
+ 0x76, // push0 ("y")
+ 0x76, // push0
+ 0x81, 0x00, // lag global[0] (ego)
+ 0x4a, 0x04, // send 4
+ SIG_MAGICDWORD,
+ 0x36, // push
+ 0x35, 42, // ldi 42 <-- comparing ego.y with 42
+ 0x22, // lt?
+ SIG_END
+};
+
+static const uint16 qfg3PatchRoom750Bounds1[] = {
+ // (if (< (ego y?) 50)
+ PATCH_ADDTOOFFSET(+8),
+ 50, // 42 --> 50
+ PATCH_END
+};
+
+static const uint16 qfg3SignatureRoom750Bounds2[] = {
+ // (ego x: 294 y: 39)
+ 0x78, // push1 ("x")
+ 0x78, // push1
+ 0x38, SIG_UINT16(294), // pushi 294
+ 0x76, // push0 ("y")
+ 0x78, // push1
+ SIG_MAGICDWORD,
+ 0x39, 29, // pushi 29
+ 0x81, 0x00, // lag global[0] (ego)
+ 0x4a, 0x0c, // send 12
+ SIG_END
+};
+
+static const uint16 qfg3PatchRoom750Bounds2[] = {
+ // (ego x: 320 y: 39)
+ PATCH_ADDTOOFFSET(+3),
+ PATCH_UINT16(320), // 294 --> 320
+ PATCH_ADDTOOFFSET(+3),
+ 39, // 29 --> 39
+ PATCH_END
+};
+
+static const uint16 qfg3SignatureRoom750Bounds3[] = {
+ // (ego setMotion: MoveTo 282 29 self)
+ 0x38, SIG_SELECTOR16(setMotion), // pushi "setMotion" 0x133 in QfG3
+ 0x39, 0x04, // pushi 4
+ 0x51, SIG_ADDTOOFFSET(+1), // class MoveTo
+ 0x36, // push
+ 0x38, SIG_UINT16(282), // pushi 282
+ SIG_MAGICDWORD,
+ 0x39, 29, // pushi 29
+ 0x7c, // pushSelf
+ 0x81, 0x00, // lag global[0] (ego)
+ 0x4a, 0x0c, // send 12
+ SIG_END
+};
+
+static const uint16 qfg3PatchRoom750Bounds3[] = {
+ // (ego setMotion: MoveTo 309 35 self)
+ PATCH_ADDTOOFFSET(+9),
+ PATCH_UINT16(309), // 282 --> 309
+ PATCH_ADDTOOFFSET(+1),
+ 35, // 29 --> 35
+ PATCH_END
+};
+
// script, description, signature patch
static const SciScriptPatcherEntry qfg3Signatures[] = {
- { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
- { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog },
- { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialogAlt, qfg3PatchWooDialogAlt },
- { true, 52, "export character save bug", 2, qfg3SignatureExportChar, qfg3PatchExportChar },
- { true, 54, "import character from QfG1 bug", 1, qfg3SignatureImportQfG1Char, qfg3PatchImportQfG1Char },
- { true, 640, "chief in hut priority fix", 1, qfg3SignatureChiefPriority, qfg3PatchChiefPriority },
- { true, 550, "combat speed throttling script", 1, qfg3SignatureCombatSpeedThrottling1, qfg3PatchCombatSpeedThrottling1 },
- { true, 550, "combat speed throttling heap", 1, qfg3SignatureCombatSpeedThrottling2, qfg3PatchCombatSpeedThrottling2 },
+ { true, 944, "import dialog continuous calls", 1, qfg3SignatureImportDialog, qfg3PatchImportDialog },
+ { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialog, qfg3PatchWooDialog },
+ { true, 440, "dialog crash when asking about Woo", 1, qfg3SignatureWooDialogAlt, qfg3PatchWooDialogAlt },
+ { true, 52, "export character save bug", 2, qfg3SignatureExportChar, qfg3PatchExportChar },
+ { true, 54, "import character from QfG1 bug", 1, qfg3SignatureImportQfG1Char, qfg3PatchImportQfG1Char },
+ { true, 640, "chief in hut priority fix", 1, qfg3SignatureChiefPriority, qfg3PatchChiefPriority },
+ { true, 285, "missing points for telling about initiation heap", 1, qfg3SignatureMissingPoints1, qfg3PatchMissingPoints1 },
+ { true, 285, "missing points for telling about initiation script", 1, qfg3SignatureMissingPoints2a, qfg3PatchMissingPoints2 },
+ { true, 285, "missing points for telling about initiation script", 1, qfg3SignatureMissingPoints2b, qfg3PatchMissingPoints2 },
+ { true, 550, "combat speed throttling script", 1, qfg3SignatureCombatSpeedThrottling1, qfg3PatchCombatSpeedThrottling1 },
+ { true, 550, "combat speed throttling heap", 1, qfg3SignatureCombatSpeedThrottling2, qfg3PatchCombatSpeedThrottling2 },
+ { true, 750, "hero goes out of bounds in room 750", 2, qfg3SignatureRoom750Bounds1, qfg3PatchRoom750Bounds1 },
+ { true, 750, "hero goes out of bounds in room 750", 2, qfg3SignatureRoom750Bounds2, qfg3PatchRoom750Bounds2 },
+ { true, 750, "hero goes out of bounds in room 750", 2, qfg3SignatureRoom750Bounds3, qfg3PatchRoom750Bounds3 },
SCI_SIGNATUREENTRY_TERMINATOR
};
@@ -3406,24 +4038,35 @@ static const uint16 sq1vgaSignatureSpiderDroidTiming[] = {
0x30, SIG_UINT16(0x0005), // bnt [further method code]
0x35, 0x00, // ldi 00
0x32, SIG_UINT16(0x0052), // jmp [super-call]
- 0x89, 0xa6, // lsg global[a6]
+ 0x89, 0xa6, // lsg global[a6] <-- flag gets set to 1 when ego went up the skeleton tail, when going down it's set to 2
0x35, 0x01, // ldi 01
0x1a, // eq?
- 0x30, SIG_UINT16(0x0012), // bnt [2nd code], in case global A6 <> 1
+ 0x30, SIG_UINT16(0x0012), // bnt [PChase set code], in case global A6 <> 1
0x81, 0xb5, // lag global[b5]
- 0x30, SIG_UINT16(0x000d), // bnt [2nd code], in case global B5 == 0
+ 0x30, SIG_UINT16(0x000d), // bnt [PChase set code], in case global B5 == 0
0x38, SIG_UINT16(0x008c), // pushi 008c
0x78, // push1
0x72, SIG_UINT16(0x1cb6), // lofsa 1CB6 (moveToPath)
0x36, // push
0x54, 0x06, // self 06
0x32, SIG_UINT16(0x0038), // jmp [super-call]
+ // PChase set call
0x81, 0xb5, // lag global[B5]
0x18, // not
0x30, SIG_UINT16(0x0032), // bnt [super-call], in case global B5 <> 0
+ // followed by:
+ // is spider in current room
+ // is global A6h == 2? -> set PChase
SIG_END
}; // 58 bytes)
+// Global A6h <> 1 (did NOT went up the skeleton)
+// Global B5h = 0 -> set PChase
+// Global B5h <> 0 -> do not do anything
+// Global A6h = 1 (did went up the skeleton)
+// Global B5h = 0 -> set PChase
+// Global B5h <> 0 -> set moveToPath
+
static const uint16 sq1vgaPatchSpiderDroidTiming[] = {
0x63, 0x4e, // pToa script
0x2f, 0x68, // bt [super-call]
@@ -3448,8 +4091,8 @@ static const uint16 sq1vgaPatchSpiderDroidTiming[] = {
0x65, 0x4c, // aTop cycleSpeed
0x65, 0x5e, // aTop moveSpeed
// new code end
- 0x89, 0xb5, // lsg global[B5]
- 0x31, 0x13, // bnt [2nd code chunk]
+ 0x81, 0xb5, // lag global[B5]
+ 0x31, 0x13, // bnt [PChase code chunk]
0x89, 0xa6, // lsg global[A6]
0x35, 0x01, // ldi 01
0x1a, // eq?
@@ -3756,7 +4399,7 @@ int32 ScriptPatcher::findSignature(const SciScriptPatcherEntry *patchEntry, cons
return findSignature(runtimeEntry->magicDWord, runtimeEntry->magicOffset, patchEntry->signatureData, patchEntry->description, scriptData, scriptSize);
}
-// Attention: Magic DWord is returns using platform specific byte order. This is done on purpose for performance.
+// Attention: Magic DWord is returned using platform specific byte order. This is done on purpose for performance.
void ScriptPatcher::calculateMagicDWordAndVerify(const char *signatureDescription, const uint16 *signatureData, bool magicDWordIncluded, uint32 &calculatedMagicDWord, int &calculatedMagicDWordOffset) {
Selector curSelector = -1;
int magicOffset;
@@ -3837,7 +4480,7 @@ void ScriptPatcher::calculateMagicDWordAndVerify(const char *signatureDescriptio
}
if (!magicDWordLeft) {
// Magic DWORD is now known, convert to platform specific byte order
- calculatedMagicDWord = READ_LE_UINT32(magicDWord);
+ calculatedMagicDWord = READ_UINT32(magicDWord);
}
}
break;
@@ -3862,7 +4505,8 @@ void ScriptPatcher::calculateMagicDWordAndVerify(const char *signatureDescriptio
magicDWord[4 - magicDWordLeft] = (byte)curValue;
magicDWordLeft--;
if (!magicDWordLeft) {
- calculatedMagicDWord = READ_LE_UINT32(magicDWord);
+ // Magic DWORD is now known, convert to platform specific byte order
+ calculatedMagicDWord = READ_UINT32(magicDWord);
}
}
break;
@@ -3970,6 +4614,9 @@ void ScriptPatcher::processScript(uint16 scriptNr, byte *scriptData, const uint3
case GID_KQ6:
signatureTable = kq6Signatures;
break;
+ case GID_KQ7:
+ signatureTable = kq7Signatures;
+ break;
case GID_LAURABOW:
signatureTable = laurabow1Signatures;
break;
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index f0157a6569..b017e62df7 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -499,7 +499,7 @@ void Kernel::dumpScriptClass(char *data, int seeker, int objsize) {
void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
int objectctr[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- unsigned int _seeker = 0;
+ uint32 _seeker = 0;
Resource *script = _resMan->findResource(ResourceId(kResourceTypeScript, scriptNumber), 0);
if (!script) {
@@ -510,7 +510,7 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) {
while (_seeker < script->size) {
int objType = (int16)READ_SCI11ENDIAN_UINT16(script->data + _seeker);
int objsize;
- unsigned int seeker = _seeker + 4;
+ uint32 seeker = _seeker + 4;
if (!objType) {
debugN("End of script object (#0) encountered.\n");
@@ -741,13 +741,13 @@ void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *ke
switch (mobj->getType()) {
case SEG_TYPE_HUNK:
{
- HunkTable *ht = (HunkTable *)mobj;
+ HunkTable &ht = *(HunkTable *)mobj;
int index = argv[parmNr].getOffset();
- if (ht->isValidEntry(index)) {
+ if (ht.isValidEntry(index)) {
// NOTE: This ", deleted" isn't as useful as it could
// be because it prints the status _after_ the kernel
// call.
- debugN(" ('%s' hunk%s)", ht->_table[index].type, ht->_table[index].mem ? "" : ", deleted");
+ debugN(" ('%s' hunk%s)", ht[index].type, ht[index].mem ? "" : ", deleted");
} else
debugN(" (INVALID hunk ref)");
break;
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 8090b1861d..95e3cd15f9 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -247,9 +247,9 @@ Object *SegManager::getObject(reg_t pos) const {
if (mobj != NULL) {
if (mobj->getType() == SEG_TYPE_CLONES) {
- CloneTable *ct = (CloneTable *)mobj;
- if (ct->isValidEntry(pos.getOffset()))
- obj = &(ct->_table[pos.getOffset()]);
+ CloneTable &ct = *(CloneTable *)mobj;
+ if (ct.isValidEntry(pos.getOffset()))
+ obj = &(ct[pos.getOffset()]);
else
warning("getObject(): Trying to get an invalid object");
} else if (mobj->getType() == SEG_TYPE_SCRIPT) {
@@ -313,7 +313,7 @@ reg_t SegManager::findObjectByName(const Common::String &name, int index) {
} else if (mobj->getType() == SEG_TYPE_CLONES) {
// It's clone table, scan all objects in it
const CloneTable *ct = (const CloneTable *)mobj;
- for (uint idx = 0; idx < ct->_table.size(); ++idx) {
+ for (uint idx = 0; idx < ct->size(); ++idx) {
if (!ct->isValidEntry(idx))
continue;
@@ -404,7 +404,7 @@ reg_t SegManager::allocateHunkEntry(const char *hunk_type, int size) {
offset = table->allocEntry();
reg_t addr = make_reg(_hunksSegId, offset);
- Hunk *h = &(table->_table[offset]);
+ Hunk *h = &table->at(offset);
if (!h)
return NULL_REG;
@@ -424,7 +424,7 @@ byte *SegManager::getHunkPointer(reg_t addr) {
return NULL;
}
- return (byte *)ht->_table[addr.getOffset()].mem;
+ return (byte *)ht->at(addr.getOffset()).mem;
}
Clone *SegManager::allocateClone(reg_t *addr) {
@@ -439,7 +439,7 @@ Clone *SegManager::allocateClone(reg_t *addr) {
offset = table->allocEntry();
*addr = make_reg(_clonesSegId, offset);
- return &(table->_table[offset]);
+ return &table->at(offset);
}
List *SegManager::allocateList(reg_t *addr) {
@@ -453,7 +453,7 @@ List *SegManager::allocateList(reg_t *addr) {
offset = table->allocEntry();
*addr = make_reg(_listsSegId, offset);
- return &(table->_table[offset]);
+ return &table->at(offset);
}
Node *SegManager::allocateNode(reg_t *addr) {
@@ -467,7 +467,7 @@ Node *SegManager::allocateNode(reg_t *addr) {
offset = table->allocEntry();
*addr = make_reg(_nodesSegId, offset);
- return &(table->_table[offset]);
+ return &table->at(offset);
}
reg_t SegManager::newNode(reg_t value, reg_t key) {
@@ -486,14 +486,14 @@ List *SegManager::lookupList(reg_t addr) {
return NULL;
}
- ListTable *lt = (ListTable *)_heap[addr.getSegment()];
+ ListTable &lt = *(ListTable *)_heap[addr.getSegment()];
- if (!lt->isValidEntry(addr.getOffset())) {
+ if (!lt.isValidEntry(addr.getOffset())) {
error("Attempt to use non-list %04x:%04x as list", PRINT_REG(addr));
return NULL;
}
- return &(lt->_table[addr.getOffset()]);
+ return &(lt[addr.getOffset()]);
}
Node *SegManager::lookupNode(reg_t addr, bool stopOnDiscarded) {
@@ -507,9 +507,9 @@ Node *SegManager::lookupNode(reg_t addr, bool stopOnDiscarded) {
return NULL;
}
- NodeTable *nt = (NodeTable *)_heap[addr.getSegment()];
+ NodeTable &nt = *(NodeTable *)_heap[addr.getSegment()];
- if (!nt->isValidEntry(addr.getOffset())) {
+ if (!nt.isValidEntry(addr.getOffset())) {
if (!stopOnDiscarded)
return NULL;
@@ -517,7 +517,7 @@ Node *SegManager::lookupNode(reg_t addr, bool stopOnDiscarded) {
return NULL;
}
- return &(nt->_table[addr.getOffset()]);
+ return &(nt[addr.getOffset()]);
}
SegmentRef SegManager::dereference(reg_t pointer) {
@@ -873,32 +873,32 @@ SciArray<reg_t> *SegManager::allocateArray(reg_t *addr) {
offset = table->allocEntry();
*addr = make_reg(_arraysSegId, offset);
- return &(table->_table[offset]);
+ return &table->at(offset);
}
SciArray<reg_t> *SegManager::lookupArray(reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_ARRAY)
error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr));
- ArrayTable *arrayTable = (ArrayTable *)_heap[addr.getSegment()];
+ ArrayTable &arrayTable = *(ArrayTable *)_heap[addr.getSegment()];
- if (!arrayTable->isValidEntry(addr.getOffset()))
+ if (!arrayTable.isValidEntry(addr.getOffset()))
error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr));
- return &(arrayTable->_table[addr.getOffset()]);
+ return &(arrayTable[addr.getOffset()]);
}
void SegManager::freeArray(reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_ARRAY)
error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr));
- ArrayTable *arrayTable = (ArrayTable *)_heap[addr.getSegment()];
+ ArrayTable &arrayTable = *(ArrayTable *)_heap[addr.getSegment()];
- if (!arrayTable->isValidEntry(addr.getOffset()))
+ if (!arrayTable.isValidEntry(addr.getOffset()))
error("Attempt to use non-array %04x:%04x as array", PRINT_REG(addr));
- arrayTable->_table[addr.getOffset()].destroy();
- arrayTable->freeEntry(addr.getOffset());
+ arrayTable[addr.getOffset()].destroy();
+ arrayTable.freeEntry(addr.getOffset());
}
SciString *SegManager::allocateString(reg_t *addr) {
@@ -913,32 +913,32 @@ SciString *SegManager::allocateString(reg_t *addr) {
offset = table->allocEntry();
*addr = make_reg(_stringSegId, offset);
- return &(table->_table[offset]);
+ return &table->at(offset);
}
SciString *SegManager::lookupString(reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_STRING)
error("lookupString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
- StringTable *stringTable = (StringTable *)_heap[addr.getSegment()];
+ StringTable &stringTable = *(StringTable *)_heap[addr.getSegment()];
- if (!stringTable->isValidEntry(addr.getOffset()))
+ if (!stringTable.isValidEntry(addr.getOffset()))
error("lookupString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
- return &(stringTable->_table[addr.getOffset()]);
+ return &(stringTable[addr.getOffset()]);
}
void SegManager::freeString(reg_t addr) {
if (_heap[addr.getSegment()]->getType() != SEG_TYPE_STRING)
error("freeString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
- StringTable *stringTable = (StringTable *)_heap[addr.getSegment()];
+ StringTable &stringTable = *(StringTable *)_heap[addr.getSegment()];
- if (!stringTable->isValidEntry(addr.getOffset()))
+ if (!stringTable.isValidEntry(addr.getOffset()))
error("freeString: Attempt to use non-string %04x:%04x as string", PRINT_REG(addr));
- stringTable->_table[addr.getOffset()].destroy();
- stringTable->freeEntry(addr.getOffset());
+ stringTable[addr.getOffset()].destroy();
+ stringTable.freeEntry(addr.getOffset());
}
#endif
diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp
index bb90698e6a..2cff799f4b 100644
--- a/engines/sci/engine/segment.cpp
+++ b/engines/sci/engine/segment.cpp
@@ -97,7 +97,7 @@ Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const {
error("Unexpected request for outgoing references from clone at %04x:%04x", PRINT_REG(addr));
}
- const Clone *clone = &(_table[addr.getOffset()]);
+ const Clone *clone = &at(addr.getOffset());
// Emit all member variables (including references to the 'super' delegate)
for (uint i = 0; i < clone->getVarCount(); i++)
@@ -112,7 +112,7 @@ Common::Array<reg_t> CloneTable::listAllOutgoingReferences(reg_t addr) const {
void CloneTable::freeAtAddress(SegManager *segMan, reg_t addr) {
#ifdef GC_DEBUG
- Object *victim_obj = &(_table[addr.getOffset()]);
+ Object *victim_obj = &at(addr.getOffset());
if (!(victim_obj->_flags & OBJECT_FLAG_FREED))
warning("[GC] Clone %04x:%04x not reachable and not freed (freeing now)", PRINT_REG(addr));
@@ -208,7 +208,7 @@ Common::Array<reg_t> ListTable::listAllOutgoingReferences(reg_t addr) const {
error("Invalid list referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
}
- const List *list = &(_table[addr.getOffset()]);
+ const List *list = &at(addr.getOffset());
tmp.push_back(list->first);
tmp.push_back(list->last);
@@ -225,7 +225,7 @@ Common::Array<reg_t> NodeTable::listAllOutgoingReferences(reg_t addr) const {
if (!isValidEntry(addr.getOffset())) {
error("Invalid node referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
}
- const Node *node = &(_table[addr.getOffset()]);
+ const Node *node = &at(addr.getOffset());
// We need all four here. Can't just stick with 'pred' OR 'succ' because node operations allow us
// to walk around from any given node
@@ -252,13 +252,13 @@ SegmentRef DynMem::dereference(reg_t pointer) {
SegmentRef ArrayTable::dereference(reg_t pointer) {
SegmentRef ret;
ret.isRaw = false;
- ret.maxSize = _table[pointer.getOffset()].getSize() * 2;
- ret.reg = _table[pointer.getOffset()].getRawData();
+ ret.maxSize = at(pointer.getOffset()).getSize() * 2;
+ ret.reg = at(pointer.getOffset()).getRawData();
return ret;
}
void ArrayTable::freeAtAddress(SegManager *segMan, reg_t sub_addr) {
- _table[sub_addr.getOffset()].destroy();
+ at(sub_addr.getOffset()).destroy();
freeEntry(sub_addr.getOffset());
}
@@ -268,7 +268,7 @@ Common::Array<reg_t> ArrayTable::listAllOutgoingReferences(reg_t addr) const {
error("Invalid array referenced for outgoing references: %04x:%04x", PRINT_REG(addr));
}
- const SciArray<reg_t> *array = &(_table[addr.getOffset()]);
+ const SciArray<reg_t> *array = &at(addr.getOffset());
for (uint32 i = 0; i < array->getSize(); i++) {
reg_t value = array->getValue(i);
@@ -305,8 +305,8 @@ void SciString::fromString(const Common::String &string) {
SegmentRef StringTable::dereference(reg_t pointer) {
SegmentRef ret;
ret.isRaw = true;
- ret.maxSize = _table[pointer.getOffset()].getSize();
- ret.raw = (byte *)_table[pointer.getOffset()].getRawData();
+ ret.maxSize = at(pointer.getOffset()).getSize();
+ ret.raw = (byte *)at(pointer.getOffset()).getRawData();
return ret;
}
diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h
index de7f60ac16..50c77d0538 100644
--- a/engines/sci/engine/segment.h
+++ b/engines/sci/engine/segment.h
@@ -203,23 +203,24 @@ struct List {
struct Hunk {
void *mem;
- unsigned int size;
+ uint32 size;
const char *type;
};
template<typename T>
struct SegmentObjTable : public SegmentObj {
typedef T value_type;
- struct Entry : public T {
+ struct Entry {
+ T data;
int next_free; /* Only used for free entries */
};
enum { HEAPENTRY_INVALID = -1 };
-
int first_free; /**< Beginning of a singly linked list for entries */
int entries_used; /**< Statistical information */
- Common::Array<Entry> _table;
+ typedef Common::Array<Entry> ArrayType;
+ ArrayType _table;
public:
SegmentObjTable(SegmentType type) : SegmentObj(type) {
@@ -272,6 +273,14 @@ public:
tmp.push_back(make_reg(segId, i));
return tmp;
}
+
+ uint size() const { return _table.size(); }
+
+ T &at(uint index) { return _table[index].data; }
+ const T &at(uint index) const { return _table[index].data; }
+
+ T &operator[](uint index) { return at(index); }
+ const T &operator[](uint index) const { return at(index); }
};
@@ -323,8 +332,8 @@ struct HunkTable : public SegmentObjTable<Hunk> {
}
void freeEntryContents(int idx) {
- free(_table[idx].mem);
- _table[idx].mem = 0;
+ free(at(idx).mem);
+ at(idx).mem = 0;
}
virtual void freeEntry(int idx) {
@@ -502,7 +511,7 @@ struct StringTable : public SegmentObjTable<SciString> {
StringTable() : SegmentObjTable<SciString>(SEG_TYPE_STRING) {}
virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr) {
- _table[sub_addr.getOffset()].destroy();
+ at(sub_addr.getOffset()).destroy();
freeEntry(sub_addr.getOffset());
}
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index 320f2c0664..ac621f58ae 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -180,6 +180,7 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(back);
FIND_SELECTOR(skip);
FIND_SELECTOR(borderColor);
+ FIND_SELECTOR(width);
FIND_SELECTOR(fixPriority);
FIND_SELECTOR(mirrored);
FIND_SELECTOR(visible);
@@ -192,7 +193,12 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(textLeft);
FIND_SELECTOR(textBottom);
FIND_SELECTOR(textRight);
+ FIND_SELECTOR(title);
+ FIND_SELECTOR(titleFont);
+ FIND_SELECTOR(titleFore);
+ FIND_SELECTOR(titleBack);
FIND_SELECTOR(magnifier);
+ FIND_SELECTOR(frameOut);
FIND_SELECTOR(casts);
#endif
}
@@ -207,10 +213,10 @@ reg_t readSelector(SegManager *segMan, reg_t object, Selector selectorId) {
}
#ifdef ENABLE_SCI32
-void updateInfoFlagViewVisible(Object *obj, int offset) {
+void updateInfoFlagViewVisible(Object *obj, int index) {
// TODO: Make this correct for all SCI versions
// Selectors 26 through 44 are selectors for View script objects in SQ6
- if (offset >= 26 && offset <= 44 && getSciVersion() >= SCI_VERSION_2) {
+ if (index >= 26 && index <= 44 && getSciVersion() >= SCI_VERSION_2) {
obj->setInfoSelectorFlag(kInfoFlagViewVisible);
}
}
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index 1952ca0599..f2d06d1cf4 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -147,6 +147,7 @@ struct SelectorCache {
Selector skip;
Selector dimmed;
Selector borderColor;
+ Selector width;
Selector fixPriority;
Selector mirrored;
@@ -155,9 +156,10 @@ struct SelectorCache {
Selector useInsetRect;
Selector inTop, inLeft, inBottom, inRight;
Selector textTop, textLeft, textBottom, textRight;
+ Selector title, titleFont, titleFore, titleBack;
Selector magnifier;
-
+ Selector frameOut;
Selector casts; // needed for sync'ing screen items/planes with scripts, when our save/restore code is patched in (see GfxFrameout::syncWithScripts)
#endif
};
@@ -201,10 +203,10 @@ void invokeSelector(EngineState *s, reg_t object, int selectorId,
/**
* SCI32 set kInfoFlagViewVisible in the -info- selector if a certain
* range of properties was written to.
- * This function checks if offset is in the right range, and sets the flag
+ * This function checks if index is in the right range, and sets the flag
* on obj.-info- if it is.
*/
-void updateInfoFlagViewVisible(Object *obj, int offset);
+void updateInfoFlagViewVisible(Object *obj, int index);
#endif
} // End of namespace Sci
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index d53e6b48c8..2c85907628 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -70,9 +70,6 @@ static const uint16 s_halfWidthSJISMap[256] = {
EngineState::EngineState(SegManager *segMan)
: _segMan(segMan),
-#ifdef ENABLE_SCI32
- _virtualIndexFile(0),
-#endif
_dirseeker() {
reset(false);
@@ -80,9 +77,6 @@ EngineState::EngineState(SegManager *segMan)
EngineState::~EngineState() {
delete _msgState;
-#ifdef ENABLE_SCI32
- delete _virtualIndexFile;
-#endif
}
void EngineState::reset(bool isRestoring) {
@@ -95,6 +89,7 @@ void EngineState::reset(bool isRestoring) {
// reset delayed restore game functionality
_delayedRestoreGame = false;
_delayedRestoreGameId = 0;
+ _delayedRestoreFromLauncher = false;
executionStackBase = 0;
_executionStackPosChanged = false;
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 0f04e32fe5..dd8d76f002 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -131,17 +131,15 @@ public:
int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween
int16 _lastSaveNewId; // last newly created filename-id by kSaveGame
-#ifdef ENABLE_SCI32
- VirtualIndexFile *_virtualIndexFile;
-#endif
-
// see detection.cpp / SciEngine::loadGameState()
bool _delayedRestoreGame; // boolean, that triggers delayed restore (triggered by ScummVM menu)
int _delayedRestoreGameId; // the saved game id, that it supposed to get restored (triggered by ScummVM menu)
+ bool _delayedRestoreFromLauncher; // is set, when the the delayed restore game was triggered from launcher
uint _chosenQfGImportItem; // Remembers the item selected in QfG import rooms
bool _cursorWorkaroundActive; // Refer to GfxCursor::setPosition()
+ int16 _cursorWorkaroundPosCount; // When the cursor is reported to be at the previously set coordinate, we won't disable the workaround unless it happened for this many times
Common::Point _cursorWorkaroundPoint;
Common::Rect _cursorWorkaroundRect;
@@ -203,6 +201,7 @@ public:
uint16 _memorySegmentSize;
byte _memorySegment[kMemorySegmentMax];
+ // TODO: Excise video code from the state manager
VideoState _videoState;
uint16 _vmdPalStart, _vmdPalEnd;
bool _syncedAudioOptions;
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 66d9fee5fd..3e12084ed6 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -239,8 +239,9 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP
// Check if a breakpoint is set on this method
g_sci->checkExportBreakpoint(script, pubfunct);
+ assert(argp[0].toUint16() == argc); // The first argument is argc
ExecStack xstack(calling_obj, calling_obj, sp, argc, argp,
- seg, make_reg32(seg, exportAddr), -1, pubfunct, -1,
+ seg, make_reg32(seg, exportAddr), -1, -1, -1, pubfunct, -1,
s->_executionStack.size() - 1, EXEC_STACK_TYPE_CALL);
s->_executionStack.push_back(xstack);
return &(s->_executionStack.back());
@@ -312,8 +313,9 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
if (activeBreakpointTypes || DebugMan.isDebugChannelEnabled(kDebugLevelScripts))
debugSelectorCall(send_obj, selector, argc, argp, varp, funcp, s->_segMan, selectorType);
+ assert(argp[0].toUint16() == argc); // The first argument is argc
ExecStack xstack(work_obj, send_obj, curSP, argc, argp,
- 0xFFFF, curFP, selector, -1, -1,
+ 0xFFFF, curFP, selector, -1, -1, -1, -1,
origin, stackType);
if (selectorType == kSelectorVariable)
@@ -335,12 +337,12 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
return s->_executionStack.empty() ? NULL : &(s->_executionStack.back());
}
-static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int argc, reg_t *argv) {
+static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int kernelSubCallNr, int argc, reg_t *argv) {
// Add stack frame to indicate we're executing a callk.
// This is useful in debugger backtraces if this
// kernel function calls a script itself.
ExecStack xstack(NULL_REG, NULL_REG, NULL, argc, argv - 1, 0xFFFF, make_reg32(0, 0),
- kernelCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL);
+ -1, kernelCallNr, kernelSubCallNr, -1, -1, s->_executionStack.size() - 1, EXEC_STACK_TYPE_KERNEL);
s->_executionStack.push_back(xstack);
}
@@ -386,7 +388,8 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
// Call kernel function
if (!kernelCall.subFunctionCount) {
- addKernelCallToExecStack(s, kernelCallNr, argc, argv);
+ argv[-1] = make_reg(0, argc); // The first argument is argc
+ addKernelCallToExecStack(s, kernelCallNr, -1, argc, argv);
s->r_acc = kernelCall.function(s, argc, argv);
if (kernelCall.debugLogging)
@@ -444,7 +447,8 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) {
}
if (!kernelSubCall.function)
error("[VM] k%s: subfunction ID %d requested, but not available", kernelCall.name, subId);
- addKernelCallToExecStack(s, kernelCallNr, argc, argv);
+ argv[-1] = make_reg(0, argc); // The first argument is argc
+ addKernelCallToExecStack(s, kernelCallNr, subId, argc, argv);
s->r_acc = kernelSubCall.function(s, argc, argv);
if (kernelSubCall.debugLogging)
@@ -834,14 +838,15 @@ void run_vm(EngineState *s) {
int argc = (opparams[1] >> 1) // Given as offset, but we need count
+ 1 + s->r_rest;
StackPtr call_base = s->xs->sp - argc;
- s->xs->sp[1].incOffset(s->r_rest);
uint32 localCallOffset = s->xs->addr.pc.getOffset() + opparams[0];
+ int final_argc = (call_base->requireUint16()) + s->r_rest;
+ call_base[0] = make_reg(0, final_argc); // The first argument is argc
ExecStack xstack(s->xs->objp, s->xs->objp, s->xs->sp,
- (call_base->requireUint16()) + s->r_rest, call_base,
+ final_argc, call_base,
s->xs->local_segment, make_reg32(s->xs->addr.pc.getSegment(), localCallOffset),
- NULL_SELECTOR, -1, localCallOffset, s->_executionStack.size() - 1,
+ NULL_SELECTOR, -1, -1, -1, localCallOffset, s->_executionStack.size() - 1,
EXEC_STACK_TYPE_CALL);
s->_executionStack.push_back(xstack);
@@ -1100,7 +1105,7 @@ void run_vm(EngineState *s) {
// Accumulator To Property
validate_property(s, obj, opparams[0]) = s->r_acc;
#ifdef ENABLE_SCI32
- updateInfoFlagViewVisible(obj, opparams[0]);
+ updateInfoFlagViewVisible(obj, opparams[0]>>1);
#endif
break;
@@ -1113,7 +1118,7 @@ void run_vm(EngineState *s) {
// Stack To Property
validate_property(s, obj, opparams[0]) = POP32();
#ifdef ENABLE_SCI32
- updateInfoFlagViewVisible(obj, opparams[0]);
+ updateInfoFlagViewVisible(obj, opparams[0]>>1);
#endif
break;
@@ -1130,7 +1135,7 @@ void run_vm(EngineState *s) {
else
opProperty -= 1;
#ifdef ENABLE_SCI32
- updateInfoFlagViewVisible(obj, opparams[0]);
+ updateInfoFlagViewVisible(obj, opparams[0]>>1);
#endif
if (opcode == op_ipToa || opcode == op_dpToa)
s->r_acc = opProperty;
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index 514bf58b64..c41060dc32 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -93,16 +93,19 @@ struct ExecStack {
SegmentId local_segment; // local variables etc
- Selector debugSelector; // The selector which was used to call or -1 if not applicable
- int debugExportId; // The exportId which was called or -1 if not applicable
- int debugLocalCallOffset; // Local call offset or -1 if not applicable
- int debugOrigin; // The stack frame position the call was made from, or -1 if it was the initial call
+ Selector debugSelector; // The selector which was used to call or -1 if not applicable
+ int debugExportId; // The exportId which was called or -1 if not applicable
+ int debugLocalCallOffset; // Local call offset or -1 if not applicable
+ int debugOrigin; // The stack frame position the call was made from, or -1 if it was the initial call
+ int debugKernelFunction; // The kernel function called, or -1 if not applicable
+ int debugKernelSubFunction; // The kernel subfunction called, or -1 if not applicable
ExecStackType type;
reg_t* getVarPointer(SegManager *segMan) const;
ExecStack(reg_t objp_, reg_t sendp_, StackPtr sp_, int argc_, StackPtr argp_,
SegmentId localsSegment_, reg32_t pc_, Selector debugSelector_,
+ int debugKernelFunction_, int debugKernelSubFunction_,
int debugExportId_, int debugLocalCallOffset_, int debugOrigin_,
ExecStackType type_) {
objp = objp_;
@@ -112,12 +115,13 @@ struct ExecStack {
fp = sp = sp_;
argc = argc_;
variables_argp = argp_;
- *variables_argp = make_reg(0, argc); // The first argument is argc
if (localsSegment_ != 0xFFFF)
local_segment = localsSegment_;
else
local_segment = pc_.getSegment();
debugSelector = debugSelector_;
+ debugKernelFunction = debugKernelFunction_;
+ debugKernelSubFunction = debugKernelSubFunction_;
debugExportId = debugExportId_;
debugLocalCallOffset = debugLocalCallOffset_;
debugOrigin = debugOrigin_;
diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp
index 53a5a5c507..d74e2b194c 100644
--- a/engines/sci/engine/vm_types.cpp
+++ b/engines/sci/engine/vm_types.cpp
@@ -230,6 +230,10 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
return toUint16() - right.toUint16();
else
return toSint16() - right.toSint16();
+#ifdef ENABLE_SCI32
+ } else if (getSciVersion() >= SCI_VERSION_2) {
+ return sci32Comparison(right);
+#endif
} else if (pointerComparisonWithInteger(right)) {
return 1;
} else if (right.pointerComparisonWithInteger(*this)) {
@@ -238,6 +242,26 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const {
return lookForWorkaround(right, "comparison").toSint16();
}
+#ifdef ENABLE_SCI32
+int reg_t::sci32Comparison(const reg_t right) const {
+ // In SCI32, MemIDs are normally indexes into the memory manager's handle
+ // list, but the engine reserves indexes at and above 20000 for objects
+ // that were created inside the engine (as opposed to inside the VM). The
+ // engine compares these as a tiebreaker for graphics objects that are at
+ // the same priority, and it is necessary to at least minimally handle
+ // this situation.
+ // This is obviously a bogus comparision, but then, this entire thing is
+ // bogus. For the moment, it just needs to be deterministic.
+ if (isNumber() && !right.isNumber()) {
+ return 1;
+ } else if (right.isNumber() && !isNumber()) {
+ return -1;
+ }
+
+ return getOffset() - right.getOffset();
+}
+#endif
+
bool reg_t::pointerComparisonWithInteger(const reg_t right) const {
// This function handles the case where a script tries to compare a pointer
// to a number. Normally, we would not want to allow that. However, SCI0 -
diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h
index a646478a8e..e60f52e85c 100644
--- a/engines/sci/engine/vm_types.h
+++ b/engines/sci/engine/vm_types.h
@@ -160,6 +160,10 @@ private:
int cmp(const reg_t right, bool treatAsUnsigned) const;
reg_t lookForWorkaround(const reg_t right, const char *operation) const;
bool pointerComparisonWithInteger(const reg_t right) const;
+
+#ifdef ENABLE_SCI32
+ int sci32Comparison(const reg_t right) const;
+#endif
};
static inline reg_t make_reg(SegmentId segment, uint16 offset) {
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index aab32032f7..f304f774af 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -298,6 +298,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_KQ6, -1, 907, 0, "tomato", "doVerb", NULL, 2, { WORKAROUND_FAKE, 0 } }, // when looking at the rotten tomato in the inventory - bug #5331
{ GID_KQ6, -1, 928, 0, NULL, "startText", NULL, 0, { WORKAROUND_FAKE, 0 } }, // gets caused by Text+Audio support (see script patcher)
{ GID_KQ7, -1, 64996, 0, "User", "handleEvent", NULL, 1, { WORKAROUND_FAKE, 0 } }, // called when pushing a keyboard key
+ { GID_KQ7, 2450, 2450, 0, "exBridge", "handleEvent", NULL, 0, { WORKAROUND_FAKE, 0 } }, // called when walking up to the throne in the cave in chapter 2
{ GID_LAURABOW, 37, 0, 0, "CB1", "doit", NULL, 1, { WORKAROUND_FAKE, 0 } }, // when going up the stairs - bug #5084
{ GID_LAURABOW, -1, 967, 0, "myIcon", "cycle", NULL, 1, { WORKAROUND_FAKE, 0 } }, // having any portrait conversation coming up - initial bug #4971
{ GID_LAURABOW2, -1, 24, 0, "gcWin", "open", NULL, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
@@ -378,6 +379,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_SQ6, -1, 64950, -1, "Feature", "handleEvent", NULL, 0, { WORKAROUND_FAKE, 0 } }, // called when pressing "Start game" in the main menu, when entering the Orion's Belt bar (room 300), and perhaps other places
{ GID_SQ6, -1, 64964, 0, "DPath", "init", NULL, 1, { WORKAROUND_FAKE, 0 } }, // during the game
{ GID_TORIN, -1, 64017, 0, "oFlags", "clear", NULL, 0, { WORKAROUND_FAKE, 0 } }, // entering Torin's home in the French version
+ { GID_TORIN, 10000, 64029, 0, "oMessager", "nextMsg", NULL, 3, { WORKAROUND_FAKE, 0 } }, // start of chapter one
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -406,6 +408,7 @@ const SciWorkaroundEntry kCelWide_workarounds[] = {
{ GID_PQ2, -1, 255, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // when showing picture within windows, called with 2nd/3rd parameters as objects
{ GID_SQ1, 1, 255, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // DEMO: Called with 2nd/3rd parameters as objects when clicking on the menu - bug #5012
{ GID_FANMADE, -1, 979, 0, "DIcon", "setSize", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // In The Gem Scenario and perhaps other fanmade games, this is called with 2nd/3rd parameters as objects - bug #5144
+ { GID_LSL6HIRES, -1, 94, 0, "ll6ControlPanel", "init", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // when opening the "controls" panel from the main menu, the third argument is missing
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -512,6 +515,14 @@ const SciWorkaroundEntry kDisposeScript_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
+const SciWorkaroundEntry kDoSoundPlay_workarounds[] = {
+ { GID_LSL6HIRES, -1, 64989, 0, NULL, "play", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // always passes an extra null argument
+ { GID_QFG4, -1, 64989, 0, NULL, "play", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // always passes an extra null argument
+ { GID_PQ4, -1, 64989, 0, NULL, "play", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // always passes an extra null argument
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kDoSoundFade_workarounds[] = {
{ GID_KQ5, 213, 989, 0, "globalSound3", "fade", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // english floppy: when bandits leave the secret temple, parameter 4 is an object - bug #5078
{ GID_KQ6, 105, 989, 0, "globalSound", "fade", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // floppy: during intro, parameter 4 is an object
@@ -630,7 +641,7 @@ const SciWorkaroundEntry kGraphUpdateBox_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kIsObject_workarounds[] = {
- { GID_GK1, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950
+ { GID_GK1DEMO, 50, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // GK1 demo, when asking Grace for messages it gets called with an invalid parameter (type "error") - bug #4950
{ GID_ISLANDBRAIN, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when going to the game options, choosing "Info" and selecting anything from the list, gets called with an invalid parameter (type "error") - bug #4989
{ GID_QFG3, -1, 999, 0, "List", "eachElementDo", NULL, 0, { WORKAROUND_FAKE, 0 } }, // when asking for something, gets called with type error parameter
SCI_WORKAROUNDENTRY_TERMINATOR
@@ -656,6 +667,12 @@ const SciWorkaroundEntry kNewWindow_workarounds[] = {
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
+const SciWorkaroundEntry kPalVarySetPercent_workarounds[] = {
+ { GID_GK1, 370, 370, 0, "graceComeOut", "changeState", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // there's an extra parameter in GK1, when changing chapters. This extra parameter seems to be a bug or just unimplemented functionality, as there's no visible change from the original in the chapter change room
+ SCI_WORKAROUNDENTRY_TERMINATOR
+};
+
+// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kReadNumber_workarounds[] = {
{ GID_CNICK_LAURABOW,100, 101, 0, "dominoes.opt", "doit", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // When dominoes.opt is present, the game scripts call kReadNumber with an extra integer parameter - bug #6425
{ GID_HOYLE3, 100, 101, 0, "dominoes.opt", "doit", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // When dominoes.opt is present, the game scripts call kReadNumber with an extra integer parameter - bug #6425
@@ -664,7 +681,7 @@ const SciWorkaroundEntry kReadNumber_workarounds[] = {
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[] = {
- { GID_QFG4, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947
+ { GID_QFG4DEMO, 100, 100, 0, "doMovie", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // after the Sierra logo, no flags are passed, thus the call is meaningless - bug #4947
SCI_WORKAROUNDENTRY_TERMINATOR
};
@@ -737,6 +754,12 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = {
SCI_WORKAROUNDENTRY_TERMINATOR
};
+// gameID, room,script,lvl, object-name, method-name, local-call-signature, index, workaround
+const SciWorkaroundEntry kScrollWindowAdd_workarounds[] = {
+ { GID_PHANTASMAGORIA, 45, 64907, 0, "ScrollableWindow", "addString", NULL, 0, { WORKAROUND_STILLCALL, 0 } }, // ScrollWindow interface passes the last two parameters twice
+};
+
+
SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin) {
// HACK for SCI3: Temporarily ignore this
if (getSciVersion() == SCI_VERSION_3) {
@@ -758,7 +781,7 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
Common::List<ExecStack>::const_iterator callIterator = state->_executionStack.end();
while (callIterator != state->_executionStack.begin()) {
callIterator--;
- ExecStack loopCall = *callIterator;
+ const ExecStack &loopCall = *callIterator;
if ((loopCall.debugSelector != -1) || (loopCall.debugExportId != -1)) {
lastCall->debugSelector = loopCall.debugSelector;
lastCall->debugExportId = loopCall.debugExportId;
diff --git a/engines/sci/engine/workarounds.h b/engines/sci/engine/workarounds.h
index 46059a175c..248d37fc6c 100644
--- a/engines/sci/engine/workarounds.h
+++ b/engines/sci/engine/workarounds.h
@@ -74,6 +74,7 @@ extern const SciWorkaroundEntry kDeviceInfo_workarounds[];
extern const SciWorkaroundEntry kDisplay_workarounds[];
extern const SciWorkaroundEntry kDirLoop_workarounds[];
extern const SciWorkaroundEntry kDisposeScript_workarounds[];
+extern const SciWorkaroundEntry kDoSoundPlay_workarounds[];
extern const SciWorkaroundEntry kDoSoundFade_workarounds[];
extern const SciWorkaroundEntry kFindKey_workarounds[];
extern const SciWorkaroundEntry kDeleteKey_workarounds[];
@@ -89,6 +90,7 @@ extern const SciWorkaroundEntry kIsObject_workarounds[];
extern const SciWorkaroundEntry kMemory_workarounds[];
extern const SciWorkaroundEntry kMoveCursor_workarounds[];
extern const SciWorkaroundEntry kNewWindow_workarounds[];
+extern const SciWorkaroundEntry kPalVarySetPercent_workarounds[];
extern const SciWorkaroundEntry kReadNumber_workarounds[];
extern const SciWorkaroundEntry kPaletteUnsetFlag_workarounds[];
extern const SciWorkaroundEntry kSetCursor_workarounds[];
@@ -97,6 +99,7 @@ extern const SciWorkaroundEntry kStrAt_workarounds[];
extern const SciWorkaroundEntry kStrCpy_workarounds[];
extern const SciWorkaroundEntry kStrLen_workarounds[];
extern const SciWorkaroundEntry kUnLoad_workarounds[];
+extern const SciWorkaroundEntry kScrollWindowAdd_workarounds[];
extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciTrackOriginReply *trackOrigin);
diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp
index 9a87c6de0b..4ad2a0cfa3 100644
--- a/engines/sci/event.cpp
+++ b/engines/sci/event.cpp
@@ -29,6 +29,9 @@
#include "sci/console.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
+#ifdef ENABLE_SCI32
+#include "sci/graphics/frameout.h"
+#endif
#include "sci/graphics/screen.h"
namespace Sci {
@@ -133,8 +136,13 @@ static int altify(int ch) {
}
SciEvent EventManager::getScummVMEvent() {
- SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) };
- SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) };
+#ifdef ENABLE_SCI32
+ SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() };
+ SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() };
+#else
+ SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point() };
+ SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point() };
+#endif
Common::EventManager *em = g_system->getEventManager();
Common::Event ev;
@@ -155,7 +163,20 @@ SciEvent EventManager::getScummVMEvent() {
// via pollEvent.
// We also adjust the position based on the scaling of the screen.
Common::Point mousePos = em->getMousePos();
- g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x);
+
+#if ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ const Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer();
+
+ Common::Point mousePosSci = mousePos;
+ mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight));
+ noEvent.mousePosSci = input.mousePosSci = mousePosSci;
+ } else {
+#endif
+ g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x);
+#if ENABLE_SCI32
+ }
+#endif
noEvent.mousePos = input.mousePos = mousePos;
@@ -302,6 +323,11 @@ SciEvent EventManager::getScummVMEvent() {
input.character = altify(input.character);
if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (scummVMKeyFlags & Common::KBD_CTRL) && input.character > 0 && input.character < 27)
input.character += 96; // 0x01 -> 'a'
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2 && (scummVMKeyFlags & Common::KBD_CTRL) && input.character == 'c') {
+ input.character = SCI_KEY_ETX;
+ }
+#endif
// If no actual key was pressed (e.g. if only a modifier key was pressed),
// ignore the event
@@ -328,8 +354,12 @@ void EventManager::updateScreen() {
}
}
-SciEvent EventManager::getSciEvent(unsigned int mask) {
- SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(0, 0) };
+SciEvent EventManager::getSciEvent(uint32 mask) {
+#ifdef ENABLE_SCI32
+ SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() };
+#else
+ SciEvent event = { SCI_EVENT_NONE, 0, 0, Common::Point() };
+#endif
EventManager::updateScreen();
diff --git a/engines/sci/event.h b/engines/sci/event.h
index 76c884aba4..15a94b3e73 100644
--- a/engines/sci/event.h
+++ b/engines/sci/event.h
@@ -39,11 +39,18 @@ struct SciEvent {
uint16 character;
/**
- * The mouse position at the time the event was created.
- *
- * These are display coordinates!
+ * The mouse position at the time the event was created,
+ * in display coordinates.
*/
Common::Point mousePos;
+
+#ifdef ENABLE_SCI32
+ /**
+ * The mouse position at the time the event was created,
+ * in script coordinates.
+ */
+ Common::Point mousePosSci;
+#endif
};
/*Values for type*/
@@ -59,6 +66,9 @@ struct SciEvent {
#define SCI_EVENT_ANY 0x7fff
/* Keycodes of special keys: */
+#ifdef ENABLE_SCI32
+#define SCI_KEY_ETX 3
+#endif
#define SCI_KEY_ESC 27
#define SCI_KEY_BACKSPACE 8
#define SCI_KEY_ENTER 13
@@ -121,7 +131,7 @@ public:
~EventManager();
void updateScreen();
- SciEvent getSciEvent(unsigned int mask);
+ SciEvent getSciEvent(uint32 mask);
private:
SciEvent getScummVMEvent();
diff --git a/engines/sci/graphics/cache.cpp b/engines/sci/graphics/cache.cpp
index 59af8334eb..fb1f557ad6 100644
--- a/engines/sci/graphics/cache.cpp
+++ b/engines/sci/graphics/cache.cpp
@@ -102,8 +102,4 @@ int16 GfxCache::kernelViewGetCelCount(GuiResourceId viewId, int16 loopNo) {
return getView(viewId)->getCelCount(loopNo);
}
-byte GfxCache::kernelViewGetColorAtCoordinate(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y) {
- return getView(viewId)->getColorAtCoordinate(loopNo, celNo, x, y);
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/cache.h b/engines/sci/graphics/cache.h
index 33fa4fe399..61952718a9 100644
--- a/engines/sci/graphics/cache.h
+++ b/engines/sci/graphics/cache.h
@@ -49,8 +49,6 @@ public:
int16 kernelViewGetLoopCount(GuiResourceId viewId);
int16 kernelViewGetCelCount(GuiResourceId viewId, int16 loopNo);
- byte kernelViewGetColorAtCoordinate(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 x, int16 y);
-
private:
void purgeFontCache();
void purgeViewCache();
diff --git a/engines/sci/graphics/celobj32.cpp b/engines/sci/graphics/celobj32.cpp
index f8bce26a2c..48de054a31 100644
--- a/engines/sci/graphics/celobj32.cpp
+++ b/engines/sci/graphics/celobj32.cpp
@@ -26,11 +26,12 @@
#include "sci/graphics/celobj32.h"
#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
-#include "sci/graphics/picture.h"
-#include "sci/graphics/view.h"
+#include "sci/graphics/remap32.h"
+#include "sci/graphics/text32.h"
namespace Sci {
#pragma mark CelScaler
+
CelScaler *CelObj::_scaler = nullptr;
void CelScaler::activateScaleTables(const Ratio &scaleX, const Ratio &scaleY) {
@@ -82,12 +83,13 @@ const CelScalerTable *CelScaler::getScalerTable(const Ratio &scaleX, const Ratio
#pragma mark -
#pragma mark CelObj
+bool CelObj::_drawBlackLines = false;
void CelObj::init() {
+ CelObj::deinit();
+ _drawBlackLines = false;
_nextCacheId = 1;
- delete _scaler;
_scaler = new CelScaler();
- delete _cache;
_cache = new CelCache;
_cache->resize(100);
}
@@ -95,6 +97,11 @@ void CelObj::init() {
void CelObj::deinit() {
delete _scaler;
_scaler = nullptr;
+ if (_cache != nullptr) {
+ for (CelCache::iterator it = _cache->begin(); it != _cache->end(); ++it) {
+ delete it->celObj;
+ }
+ }
delete _cache;
_cache = nullptr;
}
@@ -102,27 +109,45 @@ void CelObj::deinit() {
#pragma mark -
#pragma mark CelObj - Scalers
-template <bool FLIP, typename READER>
+template<bool FLIP, typename READER>
struct SCALER_NoScale {
+#ifndef NDEBUG
+ const byte *_rowEdge;
+#endif
const byte *_row;
READER _reader;
const int16 _lastIndex;
+ const int16 _sourceX;
+ const int16 _sourceY;
- SCALER_NoScale(const CelObj &celObj, const int16 maxWidth) :
- _reader(celObj, maxWidth),
- _lastIndex(maxWidth - 1) {}
+ SCALER_NoScale(const CelObj &celObj, const int16 maxWidth, const Common::Point &scaledPosition) :
+ _row(nullptr),
+ _reader(celObj, FLIP ? celObj._width : maxWidth),
+ _lastIndex(celObj._width - 1),
+ _sourceX(scaledPosition.x),
+ _sourceY(scaledPosition.y) {}
- inline void setSource(const int16 x, const int16 y) {
- _row = _reader.getRow(y);
+ inline void setTarget(const int16 x, const int16 y) {
+ _row = _reader.getRow(y - _sourceY);
if (FLIP) {
- _row += _lastIndex - x;
+#ifndef NDEBUG
+ _rowEdge = _row - 1;
+#endif
+ _row += _lastIndex - (x - _sourceX);
+ assert(_row > _rowEdge);
} else {
- _row += x;
+#ifndef NDEBUG
+ _rowEdge = _row + _lastIndex + 1;
+#endif
+ _row += x - _sourceX;
+ assert(_row < _rowEdge);
}
}
inline byte read() {
+ assert(_row != _rowEdge);
+
if (FLIP) {
return *_row--;
} else {
@@ -133,55 +158,124 @@ struct SCALER_NoScale {
template<bool FLIP, typename READER>
struct SCALER_Scale {
+#ifndef NDEBUG
+ int16 _maxX;
+#endif
const byte *_row;
READER _reader;
- const CelScalerTable *_table;
int16 _x;
- const uint16 _lastIndex;
-
- SCALER_Scale(const CelObj &celObj, const int16 maxWidth, const Ratio scaleX, const Ratio scaleY) :
+ static int16 _valuesX[1024];
+ static int16 _valuesY[1024];
+
+ SCALER_Scale(const CelObj &celObj, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio scaleX, const Ratio scaleY) :
+ _row(nullptr),
+#ifndef NDEBUG
+ _maxX(targetRect.right - 1),
+#endif
// The maximum width of the scaled object may not be as
// wide as the source data it requires if downscaling,
// so just always make the reader decompress an entire
// line of source data when scaling
- _reader(celObj, celObj._width),
- _table(CelObj::_scaler->getScalerTable(scaleX, scaleY)),
- _lastIndex(maxWidth - 1) {}
+ _reader(celObj, celObj._width) {
+ // In order for scaling ratios to apply equally across objects that
+ // start at different positions on the screen (like the cels of a
+ // picture), the pixels that are read from the source bitmap must all
+ // use the same pattern of division. In other words, cels must follow
+ // a global scaling pattern as if they were always drawn starting at an
+ // even multiple of the scaling ratio, even if they are not.
+ //
+ // To get the correct source pixel when reading out through the scaler,
+ // the engine creates a lookup table for each axis that translates
+ // directly from target positions to the indexes of source pixels using
+ // the global cadence for the given scaling ratio.
+ //
+ // Note, however, that not all games use the global scaling mode.
+ //
+ // SQ6 definitely uses the global scaling mode (an easy visual
+ // comparison is to leave Implants N' Stuff and then look at Roger);
+ // Torin definitely does not (scaling subtitle backgrounds will cause it
+ // to attempt a read out of bounds and crash). They are both SCI
+ // "2.1mid" games, so currently the common denominator looks to be that
+ // games which use global scaling are the ones that use low-resolution
+ // script coordinates too.
+
+ const CelScalerTable *table = CelObj::_scaler->getScalerTable(scaleX, scaleY);
+
+ if (g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth == kLowResX) {
+ const int16 unscaledX = (scaledPosition.x / scaleX).toInt();
+ if (FLIP) {
+ int lastIndex = celObj._width - 1;
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = lastIndex - (table->valuesX[x] - unscaledX);
+ }
+ } else {
+ for (int16 x = targetRect.left; x < targetRect.right; ++x) {
+ _valuesX[x] = table->valuesX[x] - unscaledX;
+ }
+ }
- inline void setSource(const int16 x, const int16 y) {
- _row = _reader.getRow(_table->valuesY[y]);
- if (FLIP) {
- _x = _lastIndex - x;
+ const int16 unscaledY = (scaledPosition.y / scaleY).toInt();
+ for (int16 y = targetRect.top; y < targetRect.bottom; ++y) {
+ _valuesY[y] = table->valuesY[y] - unscaledY;
+ }
} else {
- _x = x;
+ if (FLIP) {
+ int lastIndex = celObj._width - 1;
+ for (int16 x = 0; x < targetRect.width(); ++x) {
+ _valuesX[targetRect.left + x] = lastIndex - table->valuesX[x];
+ }
+ } else {
+ for (int16 x = 0; x < targetRect.width(); ++x) {
+ _valuesX[targetRect.left + x] = table->valuesX[x];
+ }
+ }
+
+ for (int16 y = 0; y < targetRect.height(); ++y) {
+ _valuesY[targetRect.top + y] = table->valuesY[y];
+ }
}
}
+ inline void setTarget(const int16 x, const int16 y) {
+ _row = _reader.getRow(_valuesY[y]);
+ _x = x;
+ assert(_x >= 0 && _x <= _maxX);
+ }
+
inline byte read() {
- if (FLIP) {
- return _row[_table->valuesX[_x--]];
- } else {
- return _row[_table->valuesX[_x++]];
- }
+ assert(_x >= 0 && _x <= _maxX);
+ return _row[_valuesX[_x++]];
}
};
+template<bool FLIP, typename READER>
+int16 SCALER_Scale<FLIP, READER>::_valuesX[1024];
+template<bool FLIP, typename READER>
+int16 SCALER_Scale<FLIP, READER>::_valuesY[1024];
+
#pragma mark -
#pragma mark CelObj - Resource readers
struct READER_Uncompressed {
private:
+#ifndef NDEBUG
+ const int16 _sourceHeight;
+#endif
byte *_pixels;
const int16 _sourceWidth;
public:
READER_Uncompressed(const CelObj &celObj, const int16) :
+#ifndef NDEBUG
+ _sourceHeight(celObj._height),
+#endif
_sourceWidth(celObj._width) {
byte *resource = celObj.getResPointer();
_pixels = resource + READ_SCI11ENDIAN_UINT32(resource + celObj._celHeaderOffset + 24);
}
inline const byte *getRow(const int16 y) const {
+ assert(y >= 0 && y < _sourceHeight);
return _pixels + y * _sourceWidth;
}
};
@@ -205,7 +299,7 @@ public:
_sourceHeight(celObj._height),
_transparentColor(celObj._transparentColor),
_maxWidth(maxWidth) {
- assert(_maxWidth <= celObj._width);
+ assert(maxWidth <= celObj._width);
byte *celHeader = _resource + celObj._celHeaderOffset;
_dataOffset = READ_SCI11ENDIAN_UINT32(celHeader + 24);
@@ -214,6 +308,7 @@ public:
}
inline const byte *getRow(const int16 y) {
+ assert(y >= 0 && y < _sourceHeight);
if (y != _y) {
// compressed data segment for row
byte *row = _resource + _dataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + y * 4);
@@ -222,7 +317,7 @@ public:
byte *literal = _resource + _uncompressedDataOffset + READ_SCI11ENDIAN_UINT32(_resource + _controlOffset + _sourceHeight * 4 + y * 4);
uint8 length;
- for (int i = 0; i < _maxWidth; i += length) {
+ for (int16 i = 0; i < _maxWidth; i += length) {
byte controlByte = *row++;
length = controlByte;
@@ -256,6 +351,10 @@ public:
#pragma mark -
#pragma mark CelObj - Remappers
+/**
+ * Pixel mapper for a CelObj with transparent pixels and no
+ * remapping data.
+ */
struct MAPPER_NoMD {
inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
if (pixel != skipColor) {
@@ -263,162 +362,137 @@ struct MAPPER_NoMD {
}
}
};
+
+/**
+ * Pixel mapper for a CelObj with no transparent pixels and
+ * no remapping data.
+ */
struct MAPPER_NoMDNoSkip {
inline void draw(byte *target, const byte pixel, const uint8) const {
*target = pixel;
}
};
+/**
+ * Pixel mapper for a CelObj with transparent pixels,
+ * remapping data, and remapping enabled.
+ */
+struct MAPPER_Map {
+ inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
+ if (pixel != skipColor) {
+ // NOTE: For some reason, SSCI never checks if the source
+ // pixel is *above* the range of remaps.
+ if (pixel < g_sci->_gfxRemap32->getStartColor()) {
+ *target = pixel;
+ } else if (g_sci->_gfxRemap32->remapEnabled(pixel)) {
+ *target = g_sci->_gfxRemap32->remapColor(pixel, *target);
+ }
+ }
+ }
+};
+
+/**
+ * Pixel mapper for a CelObj with transparent pixels,
+ * remapping data, and remapping disabled.
+ */
+struct MAPPER_NoMap {
+ inline void draw(byte *target, const byte pixel, const uint8 skipColor) const {
+ // NOTE: For some reason, SSCI never checks if the source
+ // pixel is *above* the range of remaps.
+ if (pixel != skipColor && pixel < g_sci->_gfxRemap32->getStartColor()) {
+ *target = pixel;
+ }
+ }
+};
+
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect) const {
- const Buffer &priorityMap = g_sci->_gfxFrameout->getPriorityMap();
const Common::Point &scaledPosition = screenItem._scaledPosition;
const Ratio &scaleX = screenItem._ratioX;
const Ratio &scaleY = screenItem._ratioY;
+ _drawBlackLines = screenItem._drawBlackLines;
if (_remap) {
- if (g_sci->_gfxFrameout->_hasRemappedScreenItem) {
- const uint8 priority = MAX((int16)0, MIN((int16)255, screenItem._priority));
-
- // NOTE: In the original engine code, there was a second branch for
- // _remap here that would then call the following functions if _remap was false:
- //
- // drawHzFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // drawNoFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // drawUncompHzFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // drawUncompNoFlip(Buffer &, Buffer &, Common::Rect &, Common::Point &, uint8)
- // scaleDraw(Buffer &, Buffer &, Ratio &, Ratio &, Common::Rect &, Common::Point &, uint8)
- // scaleDrawUncomp(Buffer &, Buffer &, Ratio &, Ratio &, Common::Rect &, Common::Point &, uint8)
- //
- // However, obviously, _remap cannot be false here. This dead code branch existed in
- // at least SCI2/GK1 and SCI2.1/SQ6.
-
+ // NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
+ // but since we are already in a `_remap` branch, there is no reason to check it
+ // again
+ if (g_sci->_gfxRemap32->getRemapCount()) {
if (scaleX.isOne() && scaleY.isOne()) {
if (_compressionType == kCelCompressionNone) {
if (_drawMirrored) {
- drawUncompHzFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompHzFlipMap(target, targetRect, scaledPosition);
} else {
- drawUncompNoFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompNoFlipMap(target, targetRect, scaledPosition);
}
} else {
if (_drawMirrored) {
- drawHzFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawHzFlipMap(target, targetRect, scaledPosition);
} else {
- drawNoFlipMap(target, priorityMap, targetRect, scaledPosition, priority);
+ drawNoFlipMap(target, targetRect, scaledPosition);
}
}
} else {
if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompMap(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
} else {
- scaleDrawMap(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
}
}
} else {
- // NOTE: In the original code this check was `g_Remap_numActiveRemaps && _remap`,
- // but since we are already in a `_remap` branch, there is no reason to check it
- // again
- if (/* TODO: g_Remap_numActiveRemaps */ false) {
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
- if (_drawMirrored) {
- drawUncompHzFlipMap(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlipMap(target, targetRect, scaledPosition);
- }
+ if (scaleX.isOne() && scaleY.isOne()) {
+ if (_compressionType == kCelCompressionNone) {
+ if (_drawMirrored) {
+ drawUncompHzFlip(target, targetRect, scaledPosition);
} else {
- if (_drawMirrored) {
- drawHzFlipMap(target, targetRect, scaledPosition);
- } else {
- drawNoFlipMap(target, targetRect, scaledPosition);
- }
+ drawUncompNoFlip(target, targetRect, scaledPosition);
}
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ if (_drawMirrored) {
+ drawHzFlip(target, targetRect, scaledPosition);
} else {
- scaleDrawMap(target, scaleX, scaleY, targetRect, scaledPosition);
+ drawNoFlip(target, targetRect, scaledPosition);
}
}
} else {
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
- if (_drawMirrored) {
- drawUncompHzFlip(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlip(target, targetRect, scaledPosition);
- }
- } else {
- if (_drawMirrored) {
- drawHzFlip(target, targetRect, scaledPosition);
- } else {
- drawNoFlip(target, targetRect, scaledPosition);
- }
- }
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition);
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncomp(target, scaleX, scaleY, targetRect, scaledPosition);
- } else {
- scaleDraw(target, scaleX, scaleY, targetRect, scaledPosition);
- }
+ scaleDraw(target, scaleX, scaleY, targetRect, scaledPosition);
}
}
}
} else {
- if (g_sci->_gfxFrameout->_hasRemappedScreenItem) {
- const uint8 priority = MAX((int16)0, MIN((int16)255, screenItem._priority));
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
+ if (scaleX.isOne() && scaleY.isOne()) {
+ if (_compressionType == kCelCompressionNone) {
+ if (_transparent) {
if (_drawMirrored) {
- drawUncompHzFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
} else {
- drawUncompNoFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
}
} else {
if (_drawMirrored) {
- drawHzFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompHzFlipNoMDNoSkip(target, targetRect, scaledPosition);
} else {
- drawNoFlipNoMD(target, priorityMap, targetRect, scaledPosition, priority);
+ drawUncompNoFlipNoMDNoSkip(target, targetRect, scaledPosition);
}
}
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompNoMD(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ if (_drawMirrored) {
+ drawHzFlipNoMD(target, targetRect, scaledPosition);
} else {
- scaleDrawNoMD(target, priorityMap, scaleX, scaleY, targetRect, scaledPosition, priority);
+ drawNoFlipNoMD(target, targetRect, scaledPosition);
}
}
} else {
- if (scaleX.isOne() && scaleY.isOne()) {
- if (_compressionType == kCelCompressionNone) {
- if (_transparent) {
- if (_drawMirrored) {
- drawUncompHzFlipNoMD(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlipNoMD(target, targetRect, scaledPosition);
- }
- } else {
- if (_drawMirrored) {
- drawUncompHzFlipNoMDNoSkip(target, targetRect, scaledPosition);
- } else {
- drawUncompNoFlipNoMDNoSkip(target, targetRect, scaledPosition);
- }
- }
- } else {
- if (_drawMirrored) {
- drawHzFlipNoMD(target, targetRect, scaledPosition);
- } else {
- drawNoFlipNoMD(target, targetRect, scaledPosition);
- }
- }
+ if (_compressionType == kCelCompressionNone) {
+ scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
} else {
- if (_compressionType == kCelCompressionNone) {
- scaleDrawUncompNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
- } else {
- scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
- }
+ scaleDrawNoMD(target, scaleX, scaleY, targetRect, scaledPosition);
}
}
}
+
+ _drawBlackLines = false;
}
void CelObj::draw(Buffer &target, const ScreenItem &screenItem, const Common::Rect &targetRect, bool mirrorX) {
@@ -496,46 +570,42 @@ uint8 CelObj::readPixel(uint16 x, const uint16 y, bool mirrorX) const {
void CelObj::submitPalette() const {
if (_hunkPaletteOffset) {
- Palette palette;
-
- byte *res = getResPointer();
- // NOTE: In SCI engine this uses HunkPalette::Init.
- // TODO: Use a better size value
- g_sci->_gfxPalette32->createFromData(res + _hunkPaletteOffset, 999999, &palette);
+ HunkPalette palette(getResPointer() + _hunkPaletteOffset);
g_sci->_gfxPalette32->submit(palette);
}
}
#pragma mark -
#pragma mark CelObj - Caching
+
int CelObj::_nextCacheId = 1;
CelCache *CelObj::_cache = nullptr;
int CelObj::searchCache(const CelInfo32 &celInfo, int *nextInsertIndex) const {
+ *nextInsertIndex = -1;
int oldestId = _nextCacheId + 1;
- int oldestIndex = -1;
+ int oldestIndex = 0;
for (int i = 0, len = _cache->size(); i < len; ++i) {
CelCacheEntry &entry = (*_cache)[i];
- if (entry.celObj != nullptr) {
- if (entry.celObj->_info == celInfo) {
- entry.id = ++_nextCacheId;
- return i;
- }
-
- if (oldestId > entry.id) {
- oldestId = entry.id;
- oldestIndex = i;
+ if (entry.celObj == nullptr) {
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = i;
}
- } else if (oldestIndex == -1) {
+ } else if (entry.celObj->_info == celInfo) {
+ entry.id = ++_nextCacheId;
+ return i;
+ } else if (oldestId > entry.id) {
+ oldestId = entry.id;
oldestIndex = i;
}
}
- // NOTE: Unlike the original SCI engine code, the out-param
- // here is only updated if there was not a cache hit.
- *nextInsertIndex = oldestIndex;
+ if (*nextInsertIndex == -1) {
+ *nextInsertIndex = oldestIndex;
+ }
+
return -1;
}
@@ -557,7 +627,7 @@ void CelObj::putCopyInCache(const int cacheIndex) const {
#pragma mark -
#pragma mark CelObj - Drawing
-template <typename MAPPER, typename SCALER>
+template<typename MAPPER, typename SCALER, bool DRAW_BLACK_LINES>
struct RENDERER {
MAPPER &_mapper;
SCALER &_scaler;
@@ -569,18 +639,21 @@ struct RENDERER {
_skipColor(skipColor) {}
inline void draw(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- const int16 sourceX = targetRect.left - scaledPosition.x;
- const int16 sourceY = targetRect.top - scaledPosition.y;
-
byte *targetPixel = (byte *)target.getPixels() + target.screenWidth * targetRect.top + targetRect.left;
const int16 skipStride = target.screenWidth - targetRect.width();
const int16 targetWidth = targetRect.width();
const int16 targetHeight = targetRect.height();
- for (int y = 0; y < targetHeight; ++y) {
- _scaler.setSource(sourceX, sourceY + y);
+ for (int16 y = 0; y < targetHeight; ++y) {
+ if (DRAW_BLACK_LINES && (y % 2) == 0) {
+ memset(targetPixel, 0, targetWidth);
+ targetPixel += targetWidth + skipStride;
+ continue;
+ }
- for (int x = 0; x < targetWidth; ++x) {
+ _scaler.setTarget(targetRect.left, targetRect.top + y);
+
+ for (int16 x = 0; x < targetWidth; ++x) {
_mapper.draw(targetPixel++, _scaler.read(), _skipColor);
}
@@ -589,22 +662,27 @@ struct RENDERER {
}
};
-template <typename MAPPER, typename SCALER>
+template<typename MAPPER, typename SCALER>
void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
MAPPER mapper;
- SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width());
- RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
+ SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width(), scaledPosition);
+ RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
renderer.draw(target, targetRect, scaledPosition);
}
-template <typename MAPPER, typename SCALER>
+template<typename MAPPER, typename SCALER>
void CelObj::render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const {
MAPPER mapper;
- SCALER scaler(*this, targetRect.left - scaledPosition.x + targetRect.width(), scaleX, scaleY);
- RENDERER<MAPPER, SCALER> renderer(mapper, scaler, _transparentColor);
- renderer.draw(target, targetRect, scaledPosition);
+ SCALER scaler(*this, targetRect, scaledPosition, scaleX, scaleY);
+ if (_drawBlackLines) {
+ RENDERER<MAPPER, SCALER, true> renderer(mapper, scaler, _transparentColor);
+ renderer.draw(target, targetRect, scaledPosition);
+ } else {
+ RENDERER<MAPPER, SCALER, false> renderer(mapper, scaler, _transparentColor);
+ renderer.draw(target, targetRect, scaledPosition);
+ }
}
void dummyFill(Buffer &target, const Common::Rect &targetRect) {
@@ -612,52 +690,67 @@ void dummyFill(Buffer &target, const Common::Rect &targetRect) {
}
void CelObj::drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawHzFlip");
- dummyFill(target, targetRect);
+ render<MAPPER_NoMap, SCALER_NoScale<true, READER_Compressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawNoFlip");
- dummyFill(target, targetRect);
+ render<MAPPER_NoMap, SCALER_NoScale<false, READER_Compressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompNoFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawUncompNoFlip");
- dummyFill(target, targetRect);
+ render<MAPPER_NoMap, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawUncompHzFlip");
- dummyFill(target, targetRect);
+ render<MAPPER_NoMap, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("scaleDraw");
- dummyFill(target, targetRect);
+ if (_drawMirrored) {
+ render<MAPPER_NoMap, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ } else {
+ render<MAPPER_NoMap, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ }
}
+
void CelObj::scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("scaleDrawUncomp");
- dummyFill(target, targetRect);
+ if (_drawMirrored) {
+ render<MAPPER_NoMap, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ } else {
+ render<MAPPER_NoMap, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ }
}
+
void CelObj::drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawHzFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<true, READER_Compressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawNoFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<false, READER_Compressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawUncompNoFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("drawUncompHzFlipMap");
- dummyFill(target, targetRect);
+ render<MAPPER_Map, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("scaleDrawMap");
- dummyFill(target, targetRect);
+ if (_drawMirrored) {
+ render<MAPPER_Map, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ } else {
+ render<MAPPER_Map, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ }
}
+
void CelObj::scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- debug("scaleDrawUncompMap");
- dummyFill(target, targetRect);
+ if (_drawMirrored) {
+ render<MAPPER_Map, SCALER_Scale<true, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ } else {
+ render<MAPPER_Map, SCALER_Scale<false, READER_Uncompressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
+ }
}
void CelObj::drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
@@ -675,19 +768,20 @@ void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect
void CelObj::drawUncompNoFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMDNoSkip, SCALER_NoScale<false, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMD, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
+
void CelObj::drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
render<MAPPER_NoMDNoSkip, SCALER_NoScale<true, READER_Uncompressed> >(target, targetRect, scaledPosition);
}
void CelObj::scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
- if (_drawMirrored) {
+ if (_drawMirrored)
render<MAPPER_NoMD, SCALER_Scale<true, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
- } else {
+ else
render<MAPPER_NoMD, SCALER_Scale<false, READER_Compressed> >(target, targetRect, scaledPosition, scaleX, scaleY);
- }
}
void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const {
@@ -698,22 +792,9 @@ void CelObj::scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Rati
}
}
-// TODO: These functions may all be vestigial.
-void CelObj::drawHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawUncompMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::drawUncompHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-void CelObj::scaleDrawUncompNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const {}
-
#pragma mark -
#pragma mark CelObjView
+
CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo) {
_info.type = kCelTypeView;
_info.resourceId = viewId;
@@ -727,7 +808,11 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
int cacheIndex = searchCache(_info, &cacheInsertIndex);
if (cacheIndex != -1) {
CelCacheEntry &entry = (*_cache)[cacheIndex];
- *this = *dynamic_cast<CelObjView *>(entry.celObj);
+ const CelObjView *const cachedCelObj = dynamic_cast<CelObjView *>(entry.celObj);
+ if (cachedCelObj == nullptr) {
+ error("Expected a CelObjView in cache slot %d", cacheIndex);
+ }
+ *this = *cachedCelObj;
entry.id = ++_nextCacheId;
return;
}
@@ -752,8 +837,8 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
if (_scaledWidth == 0 || _scaledHeight == 0) {
byte sizeFlag = data[5];
if (sizeFlag == 0) {
- _scaledWidth = 320;
- _scaledHeight = 200;
+ _scaledWidth = kLowResX;
+ _scaledHeight = kLowResY;
} else if (sizeFlag == 1) {
_scaledWidth = 640;
_scaledHeight = 480;
@@ -827,8 +912,12 @@ CelObjView::CelObjView(const GuiResourceId viewId, const int16 loopNo, const int
bool CelObjView::analyzeUncompressedForRemap() const {
byte *pixels = getResPointer() + READ_SCI11ENDIAN_UINT32(getResPointer() + _celHeaderOffset + 24);
for (int i = 0; i < _width * _height; ++i) {
- uint8 pixel = pixels[i];
- if (/* TODO: pixel >= Remap::minRemapColor && pixel <= Remap::maxRemapColor */ false && pixel != _transparentColor) {
+ const byte pixel = pixels[i];
+ if (
+ pixel >= g_sci->_gfxRemap32->getStartColor() &&
+ pixel <= g_sci->_gfxRemap32->getEndColor() &&
+ pixel != _transparentColor
+ ) {
return true;
}
}
@@ -836,7 +925,20 @@ bool CelObjView::analyzeUncompressedForRemap() const {
}
bool CelObjView::analyzeForRemap() const {
- // TODO: Implement decompression and analysis
+ READER_Compressed reader(*this, _width);
+ for (int y = 0; y < _height; y++) {
+ const byte *curRow = reader.getRow(y);
+ for (int x = 0; x < _width; x++) {
+ const byte pixel = curRow[x];
+ if (
+ pixel >= g_sci->_gfxRemap32->getStartColor() &&
+ pixel <= g_sci->_gfxRemap32->getEndColor() &&
+ pixel != _transparentColor
+ ) {
+ return true;
+ }
+ }
+ }
return false;
}
@@ -850,11 +952,16 @@ CelObjView *CelObjView::duplicate() const {
}
byte *CelObjView::getResPointer() const {
- return g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false)->data;
+ const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _info.resourceId), false);
+ if (resource == nullptr) {
+ error("Failed to load view %d from resource manager", _info.resourceId);
+ }
+ return resource->data;
}
#pragma mark -
#pragma mark CelObjPic
+
CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
_info.type = kCelTypePic;
_info.resourceId = picId;
@@ -869,7 +976,11 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
int cacheIndex = searchCache(_info, &cacheInsertIndex);
if (cacheIndex != -1) {
CelCacheEntry &entry = (*_cache)[cacheIndex];
- *this = *dynamic_cast<CelObjPic *>(entry.celObj);
+ const CelObjPic *const cachedCelObj = dynamic_cast<CelObjPic *>(entry.celObj);
+ if (cachedCelObj == nullptr) {
+ error("Expected a CelObjPic in cache slot %d", cacheIndex);
+ }
+ *this = *cachedCelObj;
entry.id = ++_nextCacheId;
return;
}
@@ -912,8 +1023,8 @@ CelObjPic::CelObjPic(const GuiResourceId picId, const int16 celNo) {
_scaledWidth = sizeFlag1;
_scaledHeight = sizeFlag2;
} else if (sizeFlag1 == 0) {
- _scaledWidth = 320;
- _scaledHeight = 200;
+ _scaledWidth = kLowResX;
+ _scaledHeight = kLowResY;
} else if (sizeFlag1 == 1) {
_scaledWidth = 640;
_scaledHeight = 480;
@@ -963,33 +1074,33 @@ CelObjPic *CelObjPic::duplicate() const {
}
byte *CelObjPic::getResPointer() const {
- return g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false)->data;
+ const Resource *const resource = g_sci->getResMan()->findResource(ResourceId(kResourceTypePic, _info.resourceId), false);
+ if (resource == nullptr) {
+ error("Failed to load pic %d from resource manager", _info.resourceId);
+ }
+ return resource->data;
}
#pragma mark -
#pragma mark CelObjMem
-CelObjMem::CelObjMem(const reg_t bitmap) {
+
+CelObjMem::CelObjMem(const reg_t bitmapObject) {
_info.type = kCelTypeMem;
- _info.bitmap = bitmap;
+ _info.bitmap = bitmapObject;
_mirrorX = false;
_compressionType = kCelCompressionNone;
_celHeaderOffset = 0;
_transparent = true;
- byte *bitmapData = g_sci->getEngineState()->_segMan->getHunkPointer(bitmap);
- if (bitmapData == nullptr || READ_SCI11ENDIAN_UINT32(bitmapData + 28) != 46) {
- error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap));
- }
-
- _width = READ_SCI11ENDIAN_UINT16(bitmapData);
- _height = READ_SCI11ENDIAN_UINT16(bitmapData + 2);
- _displace.x = READ_SCI11ENDIAN_UINT16(bitmapData + 4);
- _displace.y = READ_SCI11ENDIAN_UINT16(bitmapData + 6);
- _transparentColor = bitmapData[8];
- _scaledWidth = READ_SCI11ENDIAN_UINT16(bitmapData + 36);
- _scaledHeight = READ_SCI11ENDIAN_UINT16(bitmapData + 38);
- _hunkPaletteOffset = READ_SCI11ENDIAN_UINT16(bitmapData + 20);
- _remap = (READ_SCI11ENDIAN_UINT16(bitmapData + 10) & 2) ? true : false;
+ BitmapResource bitmap(bitmapObject);
+ _width = bitmap.getWidth();
+ _height = bitmap.getHeight();
+ _displace = bitmap.getDisplace();
+ _transparentColor = bitmap.getSkipColor();
+ _scaledWidth = bitmap.getScaledWidth();
+ _scaledHeight = bitmap.getScaledHeight();
+ _hunkPaletteOffset = bitmap.getHunkPaletteOffset();
+ _remap = bitmap.getRemap();
}
CelObjMem *CelObjMem::duplicate() const {
@@ -1002,6 +1113,7 @@ byte *CelObjMem::getResPointer() const {
#pragma mark -
#pragma mark CelObjColor
+
CelObjColor::CelObjColor(const uint8 color, const int16 width, const int16 height) {
_info.type = kCelTypeColor;
_info.color = color;
@@ -1036,4 +1148,4 @@ CelObjColor *CelObjColor::duplicate() const {
byte *CelObjColor::getResPointer() const {
error("Unsupported method");
}
-}
+} // End of namespace Sci
diff --git a/engines/sci/graphics/celobj32.h b/engines/sci/graphics/celobj32.h
index 1422b76a57..eb6ce3a3c9 100644
--- a/engines/sci/graphics/celobj32.h
+++ b/engines/sci/graphics/celobj32.h
@@ -31,6 +31,20 @@
namespace Sci {
typedef Common::Rational Ratio;
+// SCI32 has four different coordinate systems:
+// 1. low resolution, 2. game/script resolution,
+// 3. text/bitmap resolution, 4. screen resolution
+//
+// In CelObj, these values are used when there is
+// no baked in resolution of cels.
+//
+// In ScreenItem, it is used when deciding which
+// path to take to calculate dimensions.
+enum {
+ kLowResX = 320,
+ kLowResY = 200
+};
+
enum CelType {
kCelTypeView = 0,
kCelTypePic = 1,
@@ -104,6 +118,10 @@ struct CelInfo32 {
bitmap == other.bitmap
);
}
+
+ inline bool operator!=(const CelInfo32 &other) {
+ return !(*this == other);
+ }
};
class CelObj;
@@ -180,13 +198,16 @@ public:
CelScaler() :
_scaleTables(),
_activeIndex(0) {
- CelScalerTable &table = _scaleTables[_activeIndex];
+ CelScalerTable &table = _scaleTables[0];
table.scaleX = Ratio();
table.scaleY = Ratio();
for (int i = 0; i < ARRAYSIZE(table.valuesX); ++i) {
table.valuesX[i] = i;
table.valuesY[i] = i;
}
+ for (int i = 1; i < ARRAYSIZE(_scaleTables); ++i) {
+ _scaleTables[i] = _scaleTables[0];
+ }
}
/**
@@ -207,6 +228,18 @@ class ScreenItem;
class CelObj {
protected:
/**
+ * When true, every second line of the cel will be
+ * rendered as a black line.
+ *
+ * @see ScreenItem::_drawBlackLines
+ * @note Using a static member because otherwise this
+ * would otherwise need to be copied down through
+ * several calls. (SSCI did similar, using a global
+ * variable.)
+ */
+ static bool _drawBlackLines;
+
+ /**
* When true, this cel will be horizontally mirrored
* when it is drawn. This is an internal flag that is
* set by draw methods based on the combination of the
@@ -379,10 +412,10 @@ public:
#pragma mark -
#pragma mark CelObj - Drawing
private:
- template <typename MAPPER, typename SCALER>
+ template<typename MAPPER, typename SCALER>
void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
- template <typename MAPPER, typename SCALER>
+ template<typename MAPPER, typename SCALER>
void render(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition, const Ratio &scaleX, const Ratio &scaleY) const;
void drawHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
@@ -391,18 +424,15 @@ private:
void drawUncompHzFlip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDraw(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawUncomp(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
+
void drawHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawUncompNoFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawUncompHzFlipMap(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawUncompMap(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
- void drawHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompNoFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompHzFlipMap(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawUncompMap(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
+ // NOTE: The original includes versions of the above functions with priority parameters, which were not actually used in SCI32
+
void drawHzFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void drawUncompNoFlipNoMD(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
@@ -411,12 +441,7 @@ private:
void drawUncompHzFlipNoMDNoSkip(Buffer &target, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
void scaleDrawUncompNoMD(Buffer &target, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition) const;
- void drawHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompNoFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void drawUncompHzFlipNoMD(Buffer &target, const Buffer &priorityMap, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
- void scaleDrawUncompNoMD(Buffer &target, const Buffer &priorityMap, const Ratio &scaleX, const Ratio &scaleY, const Common::Rect &targetRect, const Common::Point &scaledPosition, const uint8 priority) const;
+ // NOTE: The original includes versions of the above functions with priority parameters, which were not actually used in SCI32
#pragma mark -
#pragma mark CelObj - Caching
@@ -475,7 +500,7 @@ private:
bool analyzeForRemap() const;
public:
- CelObjView(GuiResourceId viewId, int16 loopNo, int16 celNo);
+ CelObjView(const GuiResourceId viewId, const int16 loopNo, const int16 celNo);
virtual ~CelObjView() override {};
using CelObj::draw;
@@ -526,7 +551,7 @@ public:
*/
int16 _priority;
- CelObjPic(GuiResourceId pictureId, int16 celNo);
+ CelObjPic(const GuiResourceId pictureId, const int16 celNo);
virtual ~CelObjPic() override {};
using CelObj::draw;
@@ -547,7 +572,7 @@ public:
*/
class CelObjMem : public CelObj {
public:
- CelObjMem(reg_t bitmap);
+ CelObjMem(const reg_t bitmap);
virtual ~CelObjMem() override {};
virtual CelObjMem *duplicate() const override;
@@ -563,7 +588,7 @@ public:
*/
class CelObjColor : public CelObj {
public:
- CelObjColor(uint8 color, int16 width, int16 height);
+ CelObjColor(const uint8 color, const int16 width, const int16 height);
virtual ~CelObjColor() override {};
using CelObj::draw;
@@ -577,6 +602,6 @@ public:
virtual CelObjColor *duplicate() const override;
virtual byte *getResPointer() const override;
};
-}
+} // End of namespace Sci
#endif
diff --git a/engines/sci/graphics/compare.cpp b/engines/sci/graphics/compare.cpp
index 8333459b64..130416ff60 100644
--- a/engines/sci/graphics/compare.cpp
+++ b/engines/sci/graphics/compare.cpp
@@ -67,7 +67,7 @@ uint16 GfxCompare::isOnControl(uint16 screenMask, const Common::Rect &rect) {
return result;
}
-reg_t GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect &checkRect, List *list) {
+reg_t GfxCompare::canBeHereCheckRectList(const reg_t checkObject, const Common::Rect &checkRect, const List *list, const uint16 signalFlags) const {
reg_t curAddress = list->first;
Node *curNode = _segMan->lookupNode(curAddress);
reg_t curObject;
@@ -78,7 +78,7 @@ reg_t GfxCompare::canBeHereCheckRectList(reg_t checkObject, const Common::Rect &
curObject = curNode->value;
if (curObject != checkObject) {
signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
- if (!(signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate))) {
+ if (!(signal & signalFlags)) {
curRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
curRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
curRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
@@ -111,9 +111,6 @@ uint16 GfxCompare::kernelOnControl(byte screenMask, const Common::Rect &rect) {
void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
GfxView *view = NULL;
Common::Rect celRect(0, 0);
- // TODO/FIXME: Torin's menu code tries to draw special views with an ID of 0xFFFF, which
- // are not currently handled properly and cause a crash. These might be text views that
- // are not properly implemented.
GuiResourceId viewId = (GuiResourceId)readSelectorValue(_segMan, objectReference, SELECTOR(view));
int16 loopNo = readSelectorValue(_segMan, objectReference, SELECTOR(loop));
int16 celNo = readSelectorValue(_segMan, objectReference, SELECTOR(cel));
@@ -124,26 +121,8 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
z = (int16)readSelectorValue(_segMan, objectReference, SELECTOR(z));
view = _cache->getView(viewId);
-
-#ifdef ENABLE_SCI32
- if (view->isSci2Hires())
- view->adjustToUpscaledCoordinates(y, x);
- else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE))
- _coordAdjuster->fromScriptToDisplay(y, x);
-#endif
-
view->getCelRect(loopNo, celNo, x, y, z, celRect);
-#ifdef ENABLE_SCI32
- if (view->isSci2Hires()) {
- view->adjustBackUpscaledCoordinates(celRect.top, celRect.left);
- view->adjustBackUpscaledCoordinates(celRect.bottom, celRect.right);
- } else if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) {
- _coordAdjuster->fromDisplayToScript(celRect.top, celRect.left);
- _coordAdjuster->fromDisplayToScript(celRect.bottom, celRect.right);
- }
-#endif
-
if (lookupSelector(_segMan, objectReference, SELECTOR(nsTop), NULL, NULL) == kSelectorVariable) {
setNSRect(objectReference, celRect);
}
@@ -151,32 +130,65 @@ void GfxCompare::kernelSetNowSeen(reg_t objectReference) {
reg_t GfxCompare::kernelCanBeHere(reg_t curObject, reg_t listReference) {
Common::Rect checkRect;
- Common::Rect adjustedRect;
- uint16 signal, controlMask;
uint16 result;
checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
+ uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
if (!checkRect.isValidRect()) { // can occur in Iceman and Mother Goose - HACK? TODO: is this really occuring in sierra sci? check this
warning("kCan(t)BeHere - invalid rect %d, %d -> %d, %d", checkRect.left, checkRect.top, checkRect.right, checkRect.bottom);
return NULL_REG; // this means "can be here"
}
- adjustedRect = _coordAdjuster->onControl(checkRect);
-
- signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
- controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits));
+ Common::Rect adjustedRect = _coordAdjuster->onControl(checkRect);
+ uint16 controlMask = readSelectorValue(_segMan, curObject, SELECTOR(illegalBits));
result = isOnControl(GFX_SCREEN_MASK_CONTROL, adjustedRect) & controlMask;
if ((!result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) {
List *list = _segMan->lookupList(listReference);
if (!list)
error("kCanBeHere called with non-list as parameter");
- return canBeHereCheckRectList(curObject, checkRect, list);
+ return canBeHereCheckRectList(curObject, checkRect, list, kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate);
}
+
+ return make_reg(0, result);
+}
+
+reg_t GfxCompare::kernelCantBeHere32(const reg_t curObject, const reg_t listReference) const {
+ // Most of SCI32 graphics code converts rects from the VM to exclusive
+ // rects before operating on them, but this call leverages SCI16 engine
+ // code that operates on inclusive rects, so the rect's bottom-right
+ // point is not modified like in other SCI32 kernel calls
+ Common::Rect checkRect;
+
+ // At least LSL6 hires passes invalid rectangles which trigger the
+ // isValidRect assertion in the Rect constructor; this is avoided by
+ // assigning the properties after construction and then testing the
+ // rect for validity ourselves here. SSCI does not care about whether
+ // or not the rects are valid
+ checkRect.left = readSelectorValue(_segMan, curObject, SELECTOR(brLeft));
+ checkRect.top = readSelectorValue(_segMan, curObject, SELECTOR(brTop));
+ checkRect.right = readSelectorValue(_segMan, curObject, SELECTOR(brRight));
+ checkRect.bottom = readSelectorValue(_segMan, curObject, SELECTOR(brBottom));
+ if (!checkRect.isValidRect()) {
+ return make_reg(0, 0);
+ }
+
+ uint16 result = 0;
+ uint16 signal = readSelectorValue(_segMan, curObject, SELECTOR(signal));
+ const uint16 signalFlags = kSignalIgnoreActor | kSignalHidden;
+
+ if ((signal & signalFlags) == 0) {
+ List *list = _segMan->lookupList(listReference);
+ if (!list) {
+ error("kCantBeHere called with non-list as parameter");
+ }
+ result = !canBeHereCheckRectList(curObject, checkRect, list, signalFlags).isNull();
+ }
+
return make_reg(0, result);
}
diff --git a/engines/sci/graphics/compare.h b/engines/sci/graphics/compare.h
index 88b44aeeb1..c7005980d0 100644
--- a/engines/sci/graphics/compare.h
+++ b/engines/sci/graphics/compare.h
@@ -40,6 +40,7 @@ public:
uint16 kernelOnControl(byte screenMask, const Common::Rect &rect);
void kernelSetNowSeen(reg_t objectReference);
reg_t kernelCanBeHere(reg_t curObject, reg_t listReference);
+ reg_t kernelCantBeHere32(const reg_t curObject, const reg_t listReference) const;
bool kernelIsItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo, Common::Point position);
void kernelBaseSetter(reg_t object);
Common::Rect getNSRect(reg_t object);
@@ -58,7 +59,7 @@ private:
* *different* from checkObject, has a brRect which is contained inside
* checkRect.
*/
- reg_t canBeHereCheckRectList(reg_t checkObject, const Common::Rect &checkRect, List *list);
+ reg_t canBeHereCheckRectList(const reg_t checkObject, const Common::Rect &checkRect, const List *list, const uint16 signalFlags) const;
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/controls32.cpp b/engines/sci/graphics/controls32.cpp
index 04a70d35f3..6b91bb4679 100644
--- a/engines/sci/graphics/controls32.cpp
+++ b/engines/sci/graphics/controls32.cpp
@@ -21,11 +21,14 @@
*/
#include "common/system.h"
-
+#include "common/translation.h"
+#include "gui/message.h"
#include "sci/sci.h"
+#include "sci/console.h"
#include "sci/event.h"
#include "sci/engine/kernel.h"
#include "sci/engine/seg_manager.h"
+#include "sci/engine/state.h"
#include "sci/graphics/cache.h"
#include "sci/graphics/compare.h"
#include "sci/graphics/controls32.h"
@@ -34,171 +37,808 @@
#include "sci/graphics/text32.h"
namespace Sci {
+GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text) :
+ _segMan(segMan),
+ _gfxCache(cache),
+ _gfxText32(text),
+ _overwriteMode(false),
+ _nextCursorFlashTick(0),
+ // SSCI used a memory handle for a ScrollWindow object
+ // as ID. We use a simple numeric handle instead.
+ _nextScrollWindowId(10000) {}
-GfxControls32::GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text)
- : _segMan(segMan), _cache(cache), _text(text) {
+GfxControls32::~GfxControls32() {
+ ScrollWindowMap::iterator it;
+ for (it = _scrollWindows.begin(); it != _scrollWindows.end(); ++it)
+ delete it->_value;
}
-GfxControls32::~GfxControls32() {
+#pragma mark -
+#pragma mark Garbage collection
+
+Common::Array<reg_t> GfxControls32::listObjectReferences() {
+ Common::Array<reg_t> ret;
+ ScrollWindowMap::const_iterator it;
+ for (it = _scrollWindows.begin(); it != _scrollWindows.end(); ++it)
+ ret.push_back(it->_value->getBitmap());
+
+ return ret;
}
-void GfxControls32::kernelTexteditChange(reg_t controlObject) {
- SciEvent curEvent;
- uint16 maxChars = 40; //readSelectorValue(_segMan, controlObject, SELECTOR(max)); // TODO
- reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
- GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font)));
- Common::String text;
- uint16 textSize;
- bool textChanged = false;
- bool textAddChar = false;
- Common::Rect rect;
+#pragma mark -
+#pragma mark Text input control
+
+reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
+ SegManager *segMan = _segMan;
+
+ TextEditor editor;
+ reg_t textObject = readSelector(_segMan, controlObject, SELECTOR(text));
+ editor.text = _segMan->getString(textObject);
+ editor.foreColor = readSelectorValue(_segMan, controlObject, SELECTOR(fore));
+ editor.backColor = readSelectorValue(_segMan, controlObject, SELECTOR(back));
+ editor.skipColor = readSelectorValue(_segMan, controlObject, SELECTOR(skip));
+ editor.fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
+ editor.maxLength = readSelectorValue(_segMan, controlObject, SELECTOR(width));
+ editor.bitmap = readSelector(_segMan, controlObject, SELECTOR(bitmap));
+ editor.cursorCharPosition = 0;
+ editor.cursorIsDrawn = false;
+ editor.borderColor = readSelectorValue(_segMan, controlObject, SELECTOR(borderColor));
+
+ reg_t titleObject = readSelector(_segMan, controlObject, SELECTOR(title));
+
+ int16 titleHeight = 0;
+ GuiResourceId titleFontId = readSelectorValue(_segMan, controlObject, SELECTOR(titleFont));
+ if (!titleObject.isNull()) {
+ GfxFont *titleFont = _gfxCache->getFont(titleFontId);
+ titleHeight += _gfxText32->scaleUpHeight(titleFont->getHeight()) + 1;
+ if (editor.borderColor != -1) {
+ titleHeight += 2;
+ }
+ }
+
+ int16 width = 0;
+ int16 height = titleHeight;
+
+ GfxFont *editorFont = _gfxCache->getFont(editor.fontId);
+ height += _gfxText32->scaleUpHeight(editorFont->getHeight()) + 1;
+ _gfxText32->setFont(editor.fontId);
+ int16 emSize = _gfxText32->getCharWidth('M', true);
+ width += editor.maxLength * emSize + 1;
+ if (editor.borderColor != -1) {
+ width += 4;
+ height += 2;
+ }
- if (textReference.isNull())
- error("kEditControl called on object that doesn't have a text reference");
- text = _segMan->getString(textReference);
+ Common::Rect editorPlaneRect(width, height);
+ editorPlaneRect.translate(readSelectorValue(_segMan, controlObject, SELECTOR(x)), readSelectorValue(_segMan, controlObject, SELECTOR(y)));
- // TODO: Finish this
- warning("kEditText ('%s')", text.c_str());
- return;
+ reg_t planeObj = readSelector(_segMan, controlObject, SELECTOR(plane));
+ Plane *sourcePlane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj);
+ if (sourcePlane == nullptr) {
+ error("Could not find plane %04x:%04x", PRINT_REG(planeObj));
+ }
+ editorPlaneRect.translate(sourcePlane->_gameRect.left, sourcePlane->_gameRect.top);
- uint16 cursorPos = 0;
- //uint16 oldCursorPos = cursorPos;
- bool captureEvents = true;
- EventManager* eventMan = g_sci->getEventManager();
+ editor.textRect = Common::Rect(2, titleHeight + 2, width - 1, height - 1);
+ editor.width = width;
- while (captureEvents) {
- curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+ if (editor.bitmap.isNull()) {
+ TextAlign alignment = (TextAlign)readSelectorValue(_segMan, controlObject, SELECTOR(mode));
- if (curEvent.type == SCI_EVENT_NONE) {
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
+ if (titleObject.isNull()) {
+ bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed));
+ editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true);
} else {
- textSize = text.size();
+ error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
+ }
+ }
+
+ drawCursor(editor);
+
+ Plane *plane = new Plane(editorPlaneRect, kPlanePicTransparent);
+ plane->changePic();
+ g_sci->_gfxFrameout->addPlane(*plane);
+
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeMem;
+ celInfo.bitmap = editor.bitmap;
- switch (curEvent.type) {
- case SCI_EVENT_MOUSE_PRESS:
- // TODO: Implement mouse support for cursor change
+ ScreenItem *screenItem = new ScreenItem(plane->_object, celInfo, Common::Point(), ScaleInfo());
+ plane->_screenItemList.add(screenItem);
+
+ // frameOut must be called after the screen item is
+ // created, and before it is updated at the end of the
+ // event loop, otherwise it has both created and updated
+ // flags set which crashes the engine (it runs updates
+ // before creations)
+ g_sci->_gfxFrameout->frameOut(true);
+
+ EventManager *eventManager = g_sci->getEventManager();
+ bool clearTextOnInput = true;
+ bool textChanged = false;
+ for (;;) {
+ // We peek here because the last event needs to be allowed to
+ // dispatch a second time to the normal event handling system.
+ // In the actual engine, the event is always consumed and then
+ // the last event just gets posted back to the event manager for
+ // reprocessing, but instead, we only remove the event from the
+ // queue *after* we have determined it is not a defocusing event
+ const SciEvent event = eventManager->getSciEvent(SCI_EVENT_ANY | SCI_EVENT_PEEK);
+
+ bool focused = true;
+ // Original engine did not have a QUIT event but we have to handle it
+ if (event.type == SCI_EVENT_QUIT) {
+ focused = false;
+ break;
+ } else if (event.type == SCI_EVENT_MOUSE_PRESS && !editorPlaneRect.contains(event.mousePosSci)) {
+ focused = false;
+ } else if (event.type == SCI_EVENT_KEYBOARD) {
+ switch (event.character) {
+ case SCI_KEY_ESC:
+ case SCI_KEY_UP:
+ case SCI_KEY_DOWN:
+ case SCI_KEY_TAB:
+ case SCI_KEY_SHIFT_TAB:
+ case SCI_KEY_ENTER:
+ focused = false;
break;
- case SCI_EVENT_KEYBOARD:
- switch (curEvent.character) {
- case SCI_KEY_BACKSPACE:
- if (cursorPos > 0) {
- cursorPos--; text.deleteChar(cursorPos);
- textChanged = true;
- }
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case SCI_KEY_DELETE:
- if (cursorPos < textSize) {
- text.deleteChar(cursorPos);
- textChanged = true;
- }
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case SCI_KEY_HOME: // HOME
- cursorPos = 0; textChanged = true;
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case SCI_KEY_END: // END
- cursorPos = textSize; textChanged = true;
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case SCI_KEY_LEFT: // LEFT
- if (cursorPos > 0) {
- cursorPos--; textChanged = true;
- }
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case SCI_KEY_RIGHT: // RIGHT
- if (cursorPos + 1 <= textSize) {
- cursorPos++; textChanged = true;
- }
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case 3: // returned in SCI1 late and newer when Control - C is pressed
- if (curEvent.modifiers & SCI_KEYMOD_CTRL) {
- // Control-C erases the whole line
- cursorPos = 0; text.clear();
- textChanged = true;
+ }
+ }
+
+ if (!focused) {
+ break;
+ }
+
+ // Consume the event now that we know it is not one of the
+ // defocusing events above
+ if (event.type != SCI_EVENT_NONE)
+ eventManager->getSciEvent(SCI_EVENT_ANY);
+
+ // NOTE: In the original engine, the font and bitmap were
+ // reset here on each iteration through the loop, but it
+ // doesn't seem like this should be necessary since
+ // control is not yielded back to the VM until input is
+ // received, which means there is nothing that could modify
+ // the GfxText32's state with a different font in the
+ // meantime
+
+ bool shouldDeleteChar = false;
+ bool shouldRedrawText = false;
+ uint16 lastCursorPosition = editor.cursorCharPosition;
+ if (event.type == SCI_EVENT_KEYBOARD) {
+ switch (event.character) {
+ case SCI_KEY_LEFT:
+ clearTextOnInput = false;
+ if (editor.cursorCharPosition > 0) {
+ --editor.cursorCharPosition;
+ }
+ break;
+
+ case SCI_KEY_RIGHT:
+ clearTextOnInput = false;
+ if (editor.cursorCharPosition < editor.text.size()) {
+ ++editor.cursorCharPosition;
+ }
+ break;
+
+ case SCI_KEY_HOME:
+ clearTextOnInput = false;
+ editor.cursorCharPosition = 0;
+ break;
+
+ case SCI_KEY_END:
+ clearTextOnInput = false;
+ editor.cursorCharPosition = editor.text.size();
+ break;
+
+ case SCI_KEY_INSERT:
+ clearTextOnInput = false;
+ // Redrawing also changes the cursor rect to
+ // reflect the new insertion mode
+ shouldRedrawText = true;
+ _overwriteMode = !_overwriteMode;
+ break;
+
+ case SCI_KEY_DELETE:
+ clearTextOnInput = false;
+ if (editor.cursorCharPosition < editor.text.size()) {
+ shouldDeleteChar = true;
+ }
+ break;
+
+ case SCI_KEY_BACKSPACE:
+ clearTextOnInput = false;
+ shouldDeleteChar = true;
+ if (editor.cursorCharPosition > 0) {
+ --editor.cursorCharPosition;
+ }
+ break;
+
+ case SCI_KEY_ETX:
+ editor.text.clear();
+ editor.cursorCharPosition = 0;
+ shouldRedrawText = true;
+ break;
+
+ default: {
+ if (event.character >= 20 && event.character < 257) {
+ if (clearTextOnInput) {
+ clearTextOnInput = false;
+ editor.text.clear();
}
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
- case SCI_KEY_UP:
- case SCI_KEY_DOWN:
- case SCI_KEY_ENTER:
- case SCI_KEY_ESC:
- case SCI_KEY_TAB:
- case SCI_KEY_SHIFT_TAB:
- captureEvents = false;
- break;
- default:
- if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.character == 'c') {
- // Control-C in earlier SCI games (SCI0 - SCI1 middle)
- // Control-C erases the whole line
- cursorPos = 0; text.clear();
- textChanged = true;
- } else if (curEvent.character > 31 && curEvent.character < 256 && textSize < maxChars) {
- // insert pressed character
- textAddChar = true;
- textChanged = true;
+
+ if (
+ (_overwriteMode && editor.cursorCharPosition < editor.maxLength) ||
+ (editor.text.size() < editor.maxLength && _gfxText32->getCharWidth(event.character, true) + _gfxText32->getStringWidth(editor.text) < editor.textRect.width())
+ ) {
+ if (_overwriteMode && editor.cursorCharPosition < editor.text.size()) {
+ editor.text.setChar(event.character, editor.cursorCharPosition);
+ } else {
+ editor.text.insertChar(event.character, editor.cursorCharPosition);
+ }
+
+ ++editor.cursorCharPosition;
+ shouldRedrawText = true;
}
- eventMan->getSciEvent(SCI_EVENT_KEYBOARD); // consume the event
- break;
}
- break;
+ }
}
}
- if (textChanged) {
- rect = g_sci->_gfxCompare->getNSRect(controlObject);
+ if (shouldDeleteChar) {
+ shouldRedrawText = true;
+ if (editor.cursorCharPosition < editor.text.size()) {
+ editor.text.deleteChar(editor.cursorCharPosition);
+ }
+ }
- if (textAddChar) {
- const char *textPtr = text.c_str();
+ if (shouldRedrawText) {
+ eraseCursor(editor);
+ _gfxText32->erase(editor.textRect, true);
+ _gfxText32->drawTextBox(editor.text);
+ drawCursor(editor);
+ textChanged = true;
+ screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
+ } else if (editor.cursorCharPosition != lastCursorPosition) {
+ eraseCursor(editor);
+ drawCursor(editor);
+ screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
+ } else {
+ flashCursor(editor);
+ screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
+ }
- // We check if we are really able to add the new char
- uint16 textWidth = 0;
- while (*textPtr)
- textWidth += font->getCharWidth((byte)*textPtr++);
- textWidth += font->getCharWidth(curEvent.character);
+ g_sci->_gfxFrameout->frameOut(true);
+ g_sci->getSciDebugger()->onFrame();
+ g_sci->_gfxFrameout->throttle();
+ }
- // Does it fit?
- if (textWidth >= rect.width()) {
- return;
- }
+ g_sci->_gfxFrameout->deletePlane(*plane);
+ if (readSelectorValue(segMan, controlObject, SELECTOR(frameOut))) {
+ g_sci->_gfxFrameout->frameOut(true);
+ }
- text.insertChar(curEvent.character, cursorPos++);
+ _segMan->freeHunkEntry(editor.bitmap);
- // Note: the following checkAltInput call might make the text
- // too wide to fit, but SSCI fails to check that too.
- }
+ if (textChanged) {
+ editor.text.trim();
+ SciString *string = _segMan->lookupString(textObject);
+ string->fromString(editor.text);
+ }
- reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap));
- Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject);
- //texteditCursorErase(); // TODO: Cursor
+ return make_reg(0, textChanged);
+}
+
+void GfxControls32::drawCursor(TextEditor &editor) {
+ if (!editor.cursorIsDrawn) {
+ editor.cursorRect.left = editor.textRect.left + _gfxText32->getTextWidth(editor.text, 0, editor.cursorCharPosition);
- // Write back string
- _segMan->strcpy(textReference, text.c_str());
- // Modify the buffer and show it
- _text->createTextBitmap(controlObject, 0, 0, hunkId);
+ const int16 scaledFontHeight = _gfxText32->scaleUpHeight(_gfxText32->_font->getHeight());
- _text->drawTextBitmap(0, 0, nsRect, controlObject);
- //texteditCursorDraw(rect, text.c_str(), cursorPos); // TODO: Cursor
- g_system->updateScreen();
+ // NOTE: The original code branched on borderColor here but
+ // the two branches appeared to be identical, differing only
+ // because the compiler decided to be differently clever
+ // when optimising multiplication in each branch
+ if (_overwriteMode) {
+ editor.cursorRect.top = editor.textRect.top;
+ editor.cursorRect.setHeight(scaledFontHeight);
} else {
- // TODO: Cursor
- /*
- if (g_system->getMillis() >= _texteditBlinkTime) {
- _paint16->invertRect(_texteditCursorRect);
- _paint16->bitsShow(_texteditCursorRect);
- _texteditCursorVisible = !_texteditCursorVisible;
- texteditSetBlinkTime();
- }
- */
+ editor.cursorRect.top = editor.textRect.top + scaledFontHeight - 1;
+ editor.cursorRect.setHeight(1);
+ }
+
+ const char currentChar = editor.cursorCharPosition < editor.text.size() ? editor.text[editor.cursorCharPosition] : ' ';
+ editor.cursorRect.setWidth(_gfxText32->getCharWidth(currentChar, true));
+
+ _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true);
+
+ editor.cursorIsDrawn = true;
+ }
+
+ _nextCursorFlashTick = g_sci->getTickCount() + 30;
+}
+
+void GfxControls32::eraseCursor(TextEditor &editor) {
+ if (editor.cursorIsDrawn) {
+ _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true);
+ editor.cursorIsDrawn = false;
+ }
+
+ _nextCursorFlashTick = g_sci->getTickCount() + 30;
+}
+
+void GfxControls32::flashCursor(TextEditor &editor) {
+ if (g_sci->getTickCount() > _nextCursorFlashTick) {
+ _gfxText32->invertRect(editor.bitmap, editor.width, editor.cursorRect, editor.foreColor, editor.backColor, true);
+
+ editor.cursorIsDrawn = !editor.cursorIsDrawn;
+ _nextCursorFlashTick = g_sci->getTickCount() + 30;
+ }
+}
+
+#pragma mark -
+#pragma mark Scrollable window control
+
+ScrollWindow::ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, const Common::Point &position, const reg_t plane, const uint8 defaultForeColor, const uint8 defaultBackColor, const GuiResourceId defaultFontId, const TextAlign defaultAlignment, const int16 defaultBorderColor, const uint16 maxNumEntries) :
+ _gfxText32(segMan, g_sci->_gfxCache),
+ _maxNumEntries(maxNumEntries),
+ _firstVisibleChar(0),
+ _topVisibleLine(0),
+ _lastVisibleChar(0),
+ _bottomVisibleLine(0),
+ _numLines(0),
+ _numVisibleLines(0),
+ _plane(plane),
+ _foreColor(defaultForeColor),
+ _backColor(defaultBackColor),
+ _borderColor(defaultBorderColor),
+ _fontId(defaultFontId),
+ _alignment(defaultAlignment),
+ _visible(false),
+ _position(position),
+ _screenItem(nullptr),
+ _nextEntryId(1) {
+
+ _entries.reserve(maxNumEntries);
+
+ _gfxText32.setFont(_fontId);
+ _pointSize = _gfxText32._font->getHeight();
+
+ const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ Common::Rect bitmapRect(gameRect);
+ mulinc(bitmapRect, Ratio(_gfxText32._scaledWidth, scriptWidth), Ratio(_gfxText32._scaledHeight, scriptHeight));
+
+ _textRect.left = 2;
+ _textRect.top = 2;
+ _textRect.right = bitmapRect.width() - 2;
+ _textRect.bottom = bitmapRect.height() - 2;
+
+ uint8 skipColor = 0;
+ while (skipColor == _foreColor || skipColor == _backColor) {
+ skipColor++;
+ }
+
+ assert(bitmapRect.width() > 0 && bitmapRect.height() > 0);
+ _bitmap = _gfxText32.createFontBitmap(bitmapRect.width(), bitmapRect.height(), _textRect, "", _foreColor, _backColor, skipColor, _fontId, _alignment, _borderColor, false, false);
+
+ debugC(1, kDebugLevelGraphics, "New ScrollWindow: textRect size: %d x %d, bitmap: %04x:%04x", _textRect.width(), _textRect.height(), PRINT_REG(_bitmap));
+}
+
+ScrollWindow::~ScrollWindow() {
+ // _gfxText32._bitmap will get GCed once ScrollWindow is gone.
+ // _screenItem will be deleted by GfxFrameout
+}
+
+Ratio ScrollWindow::where() const {
+ return Ratio(_topVisibleLine, MAX(_numLines, 1));
+}
+
+void ScrollWindow::show() {
+ if (_visible) {
+ return;
+ }
+
+ if (_screenItem == nullptr) {
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeMem;
+ celInfo.bitmap = _bitmap;
+
+ _screenItem = new ScreenItem(_plane, celInfo, _position, ScaleInfo());
+ }
+
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(_plane);
+ plane->_screenItemList.add(_screenItem);
+
+ _visible = true;
+}
+
+void ScrollWindow::hide() {
+ if (!_visible) {
+ return;
+ }
+
+ g_sci->_gfxFrameout->deleteScreenItem(*_screenItem, _plane);
+ _screenItem = nullptr;
+ g_sci->_gfxFrameout->frameOut(true);
+
+ _visible = false;
+}
+
+reg_t ScrollWindow::add(const Common::String &text, const GuiResourceId fontId, const int16 foreColor, const TextAlign alignment, const bool scrollTo) {
+ if (_entries.size() == _maxNumEntries) {
+ ScrollWindowEntry removedEntry = _entries.remove_at(0);
+ _text.erase(0, removedEntry.text.size());
+ // `_firstVisibleChar` will be reset shortly if
+ // `scrollTo` is true, so there is no reason to
+ // update it
+ if (!scrollTo) {
+ _firstVisibleChar -= removedEntry.text.size();
}
+ }
+
+ _entries.push_back(ScrollWindowEntry());
+ ScrollWindowEntry &entry = _entries.back();
+
+ // NOTE: In SSCI the line ID was a memory handle for the
+ // string of this line. We use a numeric ID instead.
+ entry.id = make_reg(0, _nextEntryId++);
+
+ if (_nextEntryId > _maxNumEntries) {
+ _nextEntryId = 1;
+ }
+
+ // NOTE: In SSCI this was updated after _text was
+ // updated, which meant there was an extra unnecessary
+ // subtraction operation (subtracting `entry.text` size)
+ if (scrollTo) {
+ _firstVisibleChar = _text.size();
+ }
+
+ fillEntry(entry, text, fontId, foreColor, alignment);
+ _text += entry.text;
+
+ computeLineIndices();
+ update(true);
+
+ return entry.id;
+}
+
+void ScrollWindow::fillEntry(ScrollWindowEntry &entry, const Common::String &text, const GuiResourceId fontId, const int16 foreColor, const TextAlign alignment) {
+ entry.alignment = alignment;
+ entry.foreColor = foreColor;
+ entry.fontId = fontId;
+
+ Common::String formattedText;
+
+ // NB: There are inconsistencies here.
+ // If there is a multi-line entry with non-default properties, and it
+ // is only partially displayed, it may not be displayed right, since the
+ // property directives are only added to the first line.
+ // (Verified by trying this in SSCI SQ6 with a custom ScrollWindowAdd call.)
+ //
+ // The converse is also a potential issue (but unverified), where lines
+ // with properties -1 can inherit properties from the previously rendered
+ // line instead of the defaults.
+
+ // NOTE: SSCI added "|s<lineIndex>|" here, but |s| is
+ // not a valid control code, so it just always ended up
+ // getting skipped
+ if (entry.fontId != -1) {
+ formattedText += Common::String::format("|f%d|", entry.fontId);
+ }
+ if (entry.foreColor != -1) {
+ formattedText += Common::String::format("|c%d|", entry.foreColor);
+ }
+ if (entry.alignment != -1) {
+ formattedText += Common::String::format("|a%d|", entry.alignment);
+ }
+ formattedText += text;
+ entry.text = formattedText;
+}
+
+reg_t ScrollWindow::modify(const reg_t id, const Common::String &text, const GuiResourceId fontId, const int16 foreColor, const TextAlign alignment, const bool scrollTo) {
+
+ EntriesList::iterator it = _entries.begin();
+ uint firstCharLocation = 0;
+ for ( ; it != _entries.end(); ++it) {
+ if (it->id == id) {
+ break;
+ }
+ firstCharLocation += it->text.size();
+ }
+
+ if (it == _entries.end()) {
+ return make_reg(0, 0);
+ }
+
+ ScrollWindowEntry &entry = *it;
+
+ uint oldTextLength = entry.text.size();
+
+ fillEntry(entry, text, fontId, foreColor, alignment);
+ _text.replace(firstCharLocation, oldTextLength, entry.text);
+
+ if (scrollTo) {
+ _firstVisibleChar = firstCharLocation;
+ }
+
+ computeLineIndices();
+ update(true);
+
+ return entry.id;
+}
+
+void ScrollWindow::upArrow() {
+ if (_topVisibleLine == 0) {
+ return;
+ }
+
+ _topVisibleLine--;
+ _bottomVisibleLine--;
+
+ if (_bottomVisibleLine - _topVisibleLine + 1 < _numVisibleLines) {
+ _bottomVisibleLine = _numLines - 1;
+ }
+
+ _firstVisibleChar = _startsOfLines[_topVisibleLine];
+ _lastVisibleChar = _startsOfLines[_bottomVisibleLine + 1] - 1;
+
+ _visibleText = Common::String(_text.c_str() + _firstVisibleChar, _text.c_str() + _lastVisibleChar + 1);
+
+ Common::String lineText(_text.c_str() + _startsOfLines[_topVisibleLine], _text.c_str() + _startsOfLines[_topVisibleLine + 1] - 1);
+
+ debugC(3, kDebugLevelGraphics, "ScrollWindow::upArrow: top: %d, bottom: %d, num: %d, numvis: %d, lineText: %s", _topVisibleLine, _bottomVisibleLine, _numLines, _numVisibleLines, lineText.c_str());
+
+ _gfxText32.scrollLine(lineText, _numVisibleLines, _foreColor, _alignment, _fontId, kScrollUp);
+
+ if (_visible) {
+ assert(_screenItem);
+
+ _screenItem->update();
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+}
+
+void ScrollWindow::downArrow() {
+ if (_topVisibleLine + 1 >= _numLines) {
+ return;
+ }
+
+ _topVisibleLine++;
+ _bottomVisibleLine++;
+
+ if (_bottomVisibleLine + 1 >= _numLines) {
+ _bottomVisibleLine = _numLines - 1;
+ }
+
+ _firstVisibleChar = _startsOfLines[_topVisibleLine];
+ _lastVisibleChar = _startsOfLines[_bottomVisibleLine + 1] - 1;
+
+ _visibleText = Common::String(_text.c_str() + _firstVisibleChar, _text.c_str() + _lastVisibleChar + 1);
+
+ Common::String lineText;
+ if (_bottomVisibleLine - _topVisibleLine + 1 == _numVisibleLines) {
+ lineText = Common::String(_text.c_str() + _startsOfLines[_bottomVisibleLine], _text.c_str() + _startsOfLines[_bottomVisibleLine + 1] - 1);
+ } else {
+ // scroll in empty string
+ }
+
+ debugC(3, kDebugLevelGraphics, "ScrollWindow::downArrow: top: %d, bottom: %d, num: %d, numvis: %d, lineText: %s", _topVisibleLine, _bottomVisibleLine, _numLines, _numVisibleLines, lineText.c_str());
+
+
+ _gfxText32.scrollLine(lineText, _numVisibleLines, _foreColor, _alignment, _fontId, kScrollDown);
+
+ if (_visible) {
+ assert(_screenItem);
+
+ _screenItem->update();
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+}
+
+void ScrollWindow::go(const Ratio location) {
+ const int line = (location * _numLines).toInt();
+ if (line < 0 || line > _numLines) {
+ error("Index is Out of Range in ScrollWindow");
+ }
+
+ _firstVisibleChar = _startsOfLines[line];
+ update(true);
+
+ // HACK:
+ // It usually isn't possible to set _topVisibleLine >= _numLines, and so
+ // update() doesn't. However, in this case we should set _topVisibleLine
+ // past the end. This is clearly visible in Phantasmagoria when dragging
+ // the slider in the About dialog to the very end. The slider ends up lower
+ // than where it can be moved by scrolling down with the arrows.
+ if (location.isOne()) {
+ _topVisibleLine = _numLines;
+ }
+}
+
+void ScrollWindow::home() {
+ if (_firstVisibleChar == 0) {
+ return;
+ }
+
+ _firstVisibleChar = 0;
+ update(true);
+}
+
+void ScrollWindow::end() {
+ if (_bottomVisibleLine + 1 >= _numLines) {
+ return;
+ }
+
+ int line = _numLines - _numVisibleLines;
+ if (line < 0) {
+ line = 0;
+ }
+ _firstVisibleChar = _startsOfLines[line];
+ update(true);
+}
+
+void ScrollWindow::pageUp() {
+ if (_topVisibleLine == 0) {
+ return;
+ }
+
+ _topVisibleLine -= _numVisibleLines;
+ if (_topVisibleLine < 0) {
+ _topVisibleLine = 0;
+ }
+
+ _firstVisibleChar = _startsOfLines[_topVisibleLine];
+ update(true);
+}
+
+void ScrollWindow::pageDown() {
+ if (_topVisibleLine + 1 >= _numLines) {
+ return;
+ }
+
+ _topVisibleLine += _numVisibleLines;
+ if (_topVisibleLine + 1 >= _numLines) {
+ _topVisibleLine = _numLines - 1;
+ }
+
+ _firstVisibleChar = _startsOfLines[_topVisibleLine];
+ update(true);
+}
+
+void ScrollWindow::computeLineIndices() {
+ _gfxText32.setFont(_fontId);
+ // NOTE: Unlike SSCI, foreColor and alignment are not
+ // set since these properties do not affect the width of
+ // lines
+
+ if (_gfxText32._font->getHeight() != _pointSize) {
+ error("Illegal font size font = %d pointSize = %d, should be %d.", _fontId, _gfxText32._font->getHeight(), _pointSize);
+ }
+
+ Common::Rect lineRect(0, 0, _textRect.width(), _pointSize + 3);
+
+ _startsOfLines.clear();
+
+ // NOTE: The original engine had a 1000-line limit; we
+ // do not enforce any limit
+ for (uint charIndex = 0; charIndex < _text.size(); ) {
+ _startsOfLines.push_back(charIndex);
+ charIndex += _gfxText32.getTextCount(_text, charIndex, lineRect, false);
+ }
+
+ _numLines = _startsOfLines.size();
+
+ _startsOfLines.push_back(_text.size());
+
+ _lastVisibleChar = _gfxText32.getTextCount(_text, 0, _fontId, _textRect, false) - 1;
+
+ _bottomVisibleLine = 0;
+ while (
+ _bottomVisibleLine < _numLines - 1 &&
+ _startsOfLines[_bottomVisibleLine + 1] < _lastVisibleChar
+ ) {
+ ++_bottomVisibleLine;
+ }
+
+ _numVisibleLines = _bottomVisibleLine + 1;
+}
+
+void ScrollWindow::update(const bool doFrameOut) {
+ _topVisibleLine = 0;
+ while (
+ _topVisibleLine < _numLines - 1 &&
+ _firstVisibleChar >= _startsOfLines[_topVisibleLine + 1]
+ ) {
+ ++_topVisibleLine;
+ }
+
+ _bottomVisibleLine = _topVisibleLine + _numVisibleLines - 1;
+ if (_bottomVisibleLine >= _numLines) {
+ _bottomVisibleLine = _numLines - 1;
+ }
+
+ _firstVisibleChar = _startsOfLines[_topVisibleLine];
+
+ if (_bottomVisibleLine >= 0) {
+ _lastVisibleChar = _startsOfLines[_bottomVisibleLine + 1] - 1;
+ } else {
+ _lastVisibleChar = -1;
+ }
+
+ _visibleText = Common::String(_text.c_str() + _firstVisibleChar, _text.c_str() + _lastVisibleChar + 1);
+
+ _gfxText32.erase(_textRect, false);
+ _gfxText32.drawTextBox(_visibleText);
+
+ if (_visible) {
+ assert(_screenItem);
+
+ _screenItem->update();
+ if (doFrameOut) {
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+ }
+}
+
+reg_t GfxControls32::makeScrollWindow(const Common::Rect &gameRect, const Common::Point &position, const reg_t planeObj, const uint8 defaultForeColor, const uint8 defaultBackColor, const GuiResourceId defaultFontId, const TextAlign defaultAlignment, const int16 defaultBorderColor, const uint16 maxNumEntries) {
+
+ ScrollWindow *scrollWindow = new ScrollWindow(_segMan, gameRect, position, planeObj, defaultForeColor, defaultBackColor, defaultFontId, defaultAlignment, defaultBorderColor, maxNumEntries);
+
+ const uint16 id = _nextScrollWindowId++;
+ _scrollWindows[id] = scrollWindow;
+ return make_reg(0, id);
+}
+
+ScrollWindow *GfxControls32::getScrollWindow(const reg_t id) {
+ ScrollWindowMap::iterator it;
+ it = _scrollWindows.find(id.toUint16());
+ if (it == _scrollWindows.end())
+ error("Invalid ScrollWindow ID");
+
+ return it->_value;
+}
+
+void GfxControls32::destroyScrollWindow(const reg_t id) {
+ ScrollWindow *scrollWindow = getScrollWindow(id);
+ scrollWindow->hide();
+ _scrollWindows.erase(id.getOffset());
+ delete scrollWindow;
+}
+
+#pragma mark -
+#pragma mark Message box
+
+int16 GfxControls32::showMessageBox(const Common::String &message, const char *const okLabel, const char *const altLabel, const int16 okValue, const int16 altValue) {
+ GUI::MessageDialog dialog(message, okLabel, altLabel);
+ return (dialog.runModal() == GUI::kMessageOK) ? okValue : altValue;
+}
+
+reg_t GfxControls32::kernelMessageBox(const Common::String &message, const Common::String &title, const uint16 style) {
+ if (g_engine) {
+ g_engine->pauseEngine(true);
+ }
+
+ int16 result;
+
+ switch (style & 0xF) {
+ case kMessageBoxOK:
+ result = showMessageBox(message, _("OK"), NULL, 1, 1);
+ break;
+ case kMessageBoxYesNo:
+ result = showMessageBox(message, _("Yes"), _("No"), 6, 7);
+ break;
+ default:
+ error("Unsupported MessageBox style 0x%x", style & 0xF);
+ }
+
+ if (g_engine) {
+ g_engine->pauseEngine(false);
+ }
- textAddChar = false;
- textChanged = false;
- g_sci->sleep(10);
- } // while
+ return make_reg(0, result);
}
} // End of namespace Sci
diff --git a/engines/sci/graphics/controls32.h b/engines/sci/graphics/controls32.h
index 5af7c20f16..460b0b5625 100644
--- a/engines/sci/graphics/controls32.h
+++ b/engines/sci/graphics/controls32.h
@@ -23,12 +23,387 @@
#ifndef SCI_GRAPHICS_CONTROLS32_H
#define SCI_GRAPHICS_CONTROLS32_H
+#include "sci/graphics/text32.h"
+
namespace Sci {
class GfxCache;
class GfxScreen;
class GfxText32;
+enum MessageBoxStyle {
+ kMessageBoxOK = 0x0,
+ kMessageBoxYesNo = 0x4
+};
+
+struct TextEditor {
+ /**
+ * The bitmap where the editor is rendered.
+ */
+ reg_t bitmap;
+
+ /**
+ * The width of the editor, in bitmap pixels.
+ */
+ int16 width;
+
+ /**
+ * The text in the editor.
+ */
+ Common::String text;
+
+ /**
+ * The rect where text should be drawn into the editor,
+ * in bitmap pixels.
+ */
+ Common::Rect textRect;
+
+ /**
+ * The color of the border. -1 indicates no border.
+ */
+ int16 borderColor;
+
+ /**
+ * The text color.
+ */
+ uint8 foreColor;
+
+ /**
+ * The background color.
+ */
+ uint8 backColor;
+
+ /**
+ * The transparent color.
+ */
+ uint8 skipColor;
+
+ /**
+ * The font used to render the text in the editor.
+ */
+ GuiResourceId fontId;
+
+ /**
+ * The current position of the cursor within the editor.
+ */
+ uint16 cursorCharPosition;
+
+ /**
+ * Whether or not the cursor is currently drawn to the
+ * screen.
+ */
+ bool cursorIsDrawn;
+
+ /**
+ * The rectangle for drawing the input cursor, in bitmap
+ * pixels.
+ */
+ Common::Rect cursorRect;
+
+ /**
+ * The maximum allowed text length, in characters.
+ */
+ uint16 maxLength;
+};
+
+/**
+ * A single block of text written to a ScrollWindow.
+ */
+struct ScrollWindowEntry {
+ /**
+ * ID of the line. In SSCI this was actually a memory
+ * handle for the string of this line. We use a simple
+ * numeric ID instead.
+ */
+ reg_t id;
+
+ /**
+ * The alignment to use when rendering this line of
+ * text. If -1, the default alignment from the
+ * corresponding ScrollWindow will be used.
+ */
+ TextAlign alignment;
+
+ /**
+ * The color to use to render this line of text. If -1,
+ * the default foreground color from the corresponding
+ * ScrollWindow will be used.
+ */
+ int16 foreColor;
+
+ /**
+ * The font to use to render this line of text. If -1,
+ * the default font from the corresponding ScrollWindow
+ * will be used.
+ */
+ GuiResourceId fontId;
+
+ /**
+ * The text.
+ */
+ Common::String text;
+};
+
+class ScreenItem;
+
+/**
+ * A scrollable text window.
+ */
+class ScrollWindow {
+public:
+ ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, const Common::Point &position, const reg_t planeObj, const uint8 defaultForeColor, const uint8 defaultBackColor, const GuiResourceId defaultFontId, const TextAlign defaultAlignment, const int16 defaultBorderColor, const uint16 maxNumEntries);
+ ~ScrollWindow();
+
+ /**
+ * Adds a new text entry to the window. If `fontId`,
+ * `foreColor`, or `alignment` are `-1`, the
+ * ScrollWindow's default values will be used.
+ */
+ reg_t add(const Common::String &text, const GuiResourceId fontId, const int16 foreColor, const TextAlign alignment, const bool scrollTo);
+
+ /**
+ * Modifies an existing text entry with the given ID. If
+ * `fontId`, `foreColor`, or `alignment` are `-1`, the
+ * ScrollWindow's default values will be used.
+ */
+ reg_t modify(const reg_t id, const Common::String &text, const GuiResourceId fontId, const int16 foreColor, const TextAlign alignment, const bool scrollTo);
+
+ /**
+ * Shows the ScrollWindow if it is not already visible.
+ */
+ void show();
+
+ /**
+ * Hides the ScrollWindow if it is currently visible.
+ */
+ void hide();
+
+ /**
+ * Gets the number of lines that the content of a
+ * ScrollWindow is scrolled upward, as a ratio of the
+ * total number of lines of content.
+ */
+ Ratio where() const;
+
+ /**
+ * Scrolls the window to a specific location.
+ */
+ void go(const Ratio location);
+
+ /**
+ * Scrolls the window to the top.
+ */
+ void home();
+
+ /**
+ * Scrolls the window to the bottom.
+ */
+ void end();
+
+ /**
+ * Scrolls the window up one line.
+ */
+ void upArrow();
+
+ /**
+ * Scrolls the window down one line.
+ */
+ void downArrow();
+
+ /**
+ * Scrolls the window up by one page.
+ */
+ void pageUp();
+
+ /**
+ * Scrolls the window down by one page.
+ */
+ void pageDown();
+
+ /**
+ * Gets a reference to the in-memory bitmap that
+ * is used to render the text in the ScrollWindow.
+ */
+ const reg_t getBitmap() const { return _bitmap; }
+
+private:
+ typedef Common::Array<ScrollWindowEntry> EntriesList;
+
+ /**
+ * A convenience function that fills a
+ * ScrollWindowEntry's properties.
+ */
+ void fillEntry(ScrollWindowEntry &entry, const Common::String &text, const GuiResourceId fontId, const int16 foreColor, const TextAlign alignment);
+
+ /**
+ * Rescans the entire text of the ScrollWindow when an
+ * entry is added or modified, calculating the character
+ * offsets of all line endings, the total number of
+ * lines of text, the height of the viewport (in lines
+ * of text), the last character visible in the viewport
+ * (assuming the viewport is scrolled to the top), and
+ * the line index of the bottommost visible line
+ * (assuming the viewport is scrolled to the top).
+ */
+ void computeLineIndices();
+
+ /**
+ * Calculates which text is visible within the
+ * ScrollWindow's viewport and renders the text to the
+ * internal bitmap.
+ *
+ * If `doFrameOut` is true, the screen will be refreshed
+ * immediately instead of waiting for the next call to
+ * `kFrameOut`.
+ */
+ void update(const bool doFrameOut);
+
+ /**
+ * The text renderer.
+ */
+ GfxText32 _gfxText32;
+
+ /**
+ * The individual text entries added to the
+ * ScrollWindow.
+ */
+ EntriesList _entries;
+
+ /**
+ * The maximum number of entries allowed. Once this
+ * limit is reached, the oldest entry will be removed
+ * when a new entry is added.
+ */
+ uint _maxNumEntries;
+
+ /**
+ * A mapping from a line index to the line's character
+ * offset in `_text`.
+ */
+ Common::Array<int> _startsOfLines;
+
+ /**
+ * All text added to the window.
+ */
+ Common::String _text;
+
+ /**
+ * Text that is within the viewport of the ScrollWindow.
+ */
+ Common::String _visibleText;
+
+ /**
+ * The offset of the first visible character in `_text`.
+ */
+ int _firstVisibleChar;
+
+ /**
+ * The index of the line that is at the top of the
+ * viewport.
+ */
+ int _topVisibleLine;
+
+ /**
+ * The index of the last visible character in `_text`,
+ * or -1 if there is no text.
+ */
+ int _lastVisibleChar;
+
+ /**
+ * The index of the line that is at the bottom of the
+ * viewport, or -1 if there is no text.
+ */
+ int _bottomVisibleLine;
+
+ /**
+ * The total number of lines in the backbuffer. This
+ * number may be higher than the total number of entries
+ * if an entry contains newlines.
+ */
+ int _numLines;
+
+ /**
+ * The number of lines that are currently visible in the
+ * text area of the window.
+ */
+ int _numVisibleLines;
+
+ /**
+ * The plane in which the ScrollWindow should be
+ * rendered.
+ */
+ reg_t _plane;
+
+ /**
+ * The default text color.
+ */
+ uint8 _foreColor;
+
+ /**
+ * The default background color of the text bitmap.
+ */
+ uint8 _backColor;
+
+ /**
+ * The default border color of the text bitmap. If -1,
+ * the viewport will have no border.
+ */
+ int16 _borderColor;
+
+ /**
+ * The default font used for rendering text into the
+ * ScrollWindow.
+ */
+ GuiResourceId _fontId;
+
+ /**
+ * The default text alignment used for rendering text
+ * into the ScrollWindow.
+ */
+ TextAlign _alignment;
+
+ /**
+ * The visibility of the ScrollWindow.
+ */
+ bool _visible;
+
+ /**
+ * The dimensions of the text box inside the font
+ * bitmap, in text-system coordinates.
+ */
+ Common::Rect _textRect;
+
+ /**
+ * The top-left corner of the ScrollWindow's screen
+ * item, in game script coordinates, relative to the
+ * parent plane.
+ */
+ Common::Point _position;
+
+ /**
+ * The height of the default font in screen pixels. All
+ * fonts rendered into the ScrollWindow must have this
+ * same height.
+ */
+ uint8 _pointSize;
+
+ /**
+ * The bitmap used to render text.
+ */
+ reg_t _bitmap;
+
+ /**
+ * A monotonically increasing ID used to identify
+ * text entries added to the ScrollWindow.
+ */
+ uint16 _nextEntryId;
+
+ /**
+ * The ScrollWindow's screen item.
+ */
+ ScreenItem *_screenItem;
+};
+
/**
* Controls class, handles drawing of controls in SCI32 (SCI2, SCI2.1, SCI3) games
*/
@@ -37,12 +412,98 @@ public:
GfxControls32(SegManager *segMan, GfxCache *cache, GfxText32 *text);
~GfxControls32();
- void kernelTexteditChange(reg_t controlObject);
-
private:
SegManager *_segMan;
- GfxCache *_cache;
- GfxText32 *_text;
+ GfxCache *_gfxCache;
+ GfxText32 *_gfxText32;
+
+#pragma mark -
+#pragma mark Garbage collection
+public:
+ Common::Array<reg_t> listObjectReferences();
+
+#pragma mark -
+#pragma mark Text input control
+public:
+ reg_t kernelEditText(const reg_t controlObject);
+
+private:
+ /**
+ * If true, typing will overwrite text that already
+ * exists at the text cursor's current position.
+ */
+ bool _overwriteMode;
+
+ /**
+ * The tick at which the text cursor should be toggled
+ * by `flashCursor`.
+ */
+ uint32 _nextCursorFlashTick;
+
+ /**
+ * Draws the text cursor for the given editor.
+ */
+ void drawCursor(TextEditor &editor);
+
+ /**
+ * Erases the text cursor for the given editor.
+ */
+ void eraseCursor(TextEditor &editor);
+
+ /**
+ * Toggles the text cursor for the given editor to be
+ * either drawn or erased.
+ */
+ void flashCursor(TextEditor &editor);
+
+#pragma mark -
+#pragma mark Scrollable window control
+public:
+ /**
+ * Creates a new scrollable window and returns the ID
+ * for the new window, which is used by game scripts to
+ * interact with scrollable windows.
+ */
+ reg_t makeScrollWindow(const Common::Rect &gameRect, const Common::Point &position, const reg_t plane, const uint8 defaultForeColor, const uint8 defaultBackColor, const GuiResourceId defaultFontId, const TextAlign defaultAlignment, const int16 defaultBorderColor, const uint16 maxNumEntries);
+
+ /**
+ * Gets a registered ScrollWindow instance by ID.
+ */
+ ScrollWindow *getScrollWindow(const reg_t id);
+
+ /**
+ * Destroys the scroll window with the given ID.
+ */
+ void destroyScrollWindow(const reg_t id);
+
+private:
+ typedef Common::HashMap<uint16, ScrollWindow *> ScrollWindowMap;
+
+ /**
+ * Monotonically increasing ID used to identify
+ * ScrollWindow instances.
+ */
+ uint16 _nextScrollWindowId;
+
+ /**
+ * A lookup table for registered ScrollWindow instances.
+ */
+ ScrollWindowMap _scrollWindows;
+
+#pragma mark -
+#pragma mark Message box
+public:
+ /**
+ * Displays an OS-level message dialog.
+ */
+ reg_t kernelMessageBox(const Common::String &message, const Common::String &title, const uint16 style);
+
+private:
+ /**
+ * Convenience function for creating and showing a
+ * message box.
+ */
+ int16 showMessageBox(const Common::String &message, const char *const okLabel, const char *const altLabel, const int16 okValue, const int16 altValue);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index e8496b96e5..f5dd473959 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -336,6 +336,9 @@ void GfxCursor::setPosition(Common::Point pos) {
&& ((workaround->newPositionX == pos.x) && (workaround->newPositionY == pos.y))) {
EngineState *s = g_sci->getEngineState();
s->_cursorWorkaroundActive = true;
+ // At least on OpenPandora it seems that the cursor is actually set, but a bit afterwards
+ // touch screen controls will overwrite the position. More information see kGetEvent in kevent.cpp.
+ s->_cursorWorkaroundPosCount = 5; // should be enough for OpenPandora
s->_cursorWorkaroundPoint = pos;
s->_cursorWorkaroundRect = Common::Rect(workaround->rectLeft, workaround->rectTop, workaround->rectRight, workaround->rectBottom);
return;
diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h
index 8d125c45b3..5125469cfe 100644
--- a/engines/sci/graphics/cursor.h
+++ b/engines/sci/graphics/cursor.h
@@ -25,6 +25,8 @@
#include "common/array.h"
#include "common/hashmap.h"
+#include "sci/sci.h"
+#include "sci/graphics/helpers.h"
namespace Sci {
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index ccce8ef046..a7899b8d89 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -42,21 +42,18 @@
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/compare.h"
#include "sci/graphics/font.h"
-#include "sci/graphics/view.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/paint32.h"
#include "sci/graphics/palette32.h"
-#include "sci/graphics/picture.h"
-#include "sci/graphics/text32.h"
#include "sci/graphics/plane32.h"
+#include "sci/graphics/remap32.h"
#include "sci/graphics/screen_item32.h"
+#include "sci/graphics/text32.h"
#include "sci/graphics/frameout.h"
#include "sci/video/robot_decoder.h"
namespace Sci {
-// TODO/FIXME: This is partially guesswork
-
static int dissolveSequences[2][20] = {
/* SCI2.1early- */ { 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080 },
/* SCI2.1mid+ */ { 0, 0, 3, 6, 12, 20, 48, 96, 184, 272, 576, 1280, 3232, 6912, 13568, 24576, 46080, 73728, 132096, 466944 }
@@ -70,18 +67,18 @@ static int16 unknownCDefaults[2][16] = {
/* SCI2.1mid+ */ { 0, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 0, 0, 7, 7, 0 }
};
-GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32) :
+GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette) :
_isHiRes(false),
- _cache(cache),
_palette(palette),
_resMan(resMan),
_screen(screen),
_segMan(segMan),
- _paint32(paint32),
+ _benchmarkingFinished(false),
+ _throttleFrameOut(true),
_showStyles(nullptr),
+ _throttleState(0),
// TODO: Stop using _gfxScreen
_currentBuffer(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
- _priorityMap(screen->getDisplayWidth(), screen->getDisplayHeight(), nullptr),
_remapOccurred(false),
_frameNowVisible(false),
_screenRect(screen->getDisplayWidth(), screen->getDisplayHeight()),
@@ -117,6 +114,23 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_defaultUnknownC = unknownCDefaults[1];
}
+ switch (g_sci->getGameId()) {
+ case GID_HOYLE5:
+ case GID_GK2:
+ case GID_LIGHTHOUSE:
+ case GID_LSL7:
+ case GID_PHANTASMAGORIA2:
+ case GID_PQSWAT:
+ case GID_TORIN:
+ case GID_RAMA:
+ _currentBuffer.scriptWidth = 640;
+ _currentBuffer.scriptHeight = 480;
+ break;
+ default:
+ // default script width for other games is 320x200
+ break;
+ }
+
// TODO: Nothing in the renderer really uses this. Currently,
// the cursor renderer does, and kLocalToGlobal/kGlobalToLocal
// do, but in the real engine (1) the cursor is handled in
@@ -133,8 +147,9 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
}
GfxFrameout::~GfxFrameout() {
- CelObj::deinit();
clear();
+ CelObj::deinit();
+ free(_currentBuffer.getPixels());
}
void GfxFrameout::run() {
@@ -240,21 +255,94 @@ void GfxFrameout::syncWithScripts(bool addElements) {
}
#pragma mark -
+#pragma mark Benchmarking
+
+bool GfxFrameout::checkForFred(const reg_t object) {
+ const int16 viewId = readSelectorValue(_segMan, object, SELECTOR(view));
+ const SciGameId gameId = g_sci->getGameId();
+
+ if (gameId == GID_QFG4 && viewId == 9999) {
+ return true;
+ }
+
+ if (gameId != GID_QFG4 && viewId == -556) {
+ return true;
+ }
+
+ if (Common::String(_segMan->getObjectName(object)) == "fred") {
+ return true;
+ }
+
+ return false;
+}
+
+#pragma mark -
#pragma mark Screen items
+void GfxFrameout::addScreenItem(ScreenItem &screenItem) const {
+ Plane *plane = _planes.findByObject(screenItem._plane);
+ if (plane == nullptr) {
+ error("GfxFrameout::addScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+ }
+ plane->_screenItemList.add(&screenItem);
+}
+
+void GfxFrameout::updateScreenItem(ScreenItem &screenItem) const {
+ // TODO: In SCI3+ this will need to go through Plane
+// Plane *plane = _planes.findByObject(screenItem._plane);
+// if (plane == nullptr) {
+// error("GfxFrameout::updateScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+// }
+
+ screenItem.update();
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem) {
+ Plane *plane = _planes.findByObject(screenItem._plane);
+ if (plane == nullptr) {
+ error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
+ }
+ if (plane->_screenItemList.findByObject(screenItem._object) == nullptr) {
+ error("GfxFrameout::deleteScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItem._object), PRINT_REG(screenItem._plane));
+ }
+ deleteScreenItem(screenItem, *plane);
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, Plane &plane) {
+ if (screenItem._created == 0) {
+ screenItem._created = 0;
+ screenItem._updated = 0;
+ screenItem._deleted = getScreenCount();
+ } else {
+ plane._screenItemList.erase(&screenItem);
+ plane._screenItemList.pack();
+ }
+}
+
+void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, const reg_t planeObject) {
+ Plane *plane = _planes.findByObject(planeObject);
+ if (plane == nullptr) {
+ error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(screenItem._object));
+ }
+ deleteScreenItem(screenItem, *plane);
+}
+
void GfxFrameout::kernelAddScreenItem(const reg_t object) {
- const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+ // The "fred" object is used to test graphics performance;
+ // it is impacted by framerate throttling, so disable the
+ // throttling when this item is on the screen for the
+ // performance check to pass.
+ if (!_benchmarkingFinished && _throttleFrameOut && checkForFred(object)) {
+ _throttleFrameOut = false;
+ }
-// TODO: Remove
-// debug("Adding screen item %04x:%04x to plane %04x:%04x", PRINT_REG(object), PRINT_REG(planeObject));
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
_segMan->getObject(object)->setInfoSelectorFlag(kInfoFlagViewInserted);
Plane *plane = _planes.findByObject(planeObject);
if (plane == nullptr) {
- warning("screen item %x:%x (%s)", object.getSegment(), object.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(object));
- warning("plane %x:%x (%s)", planeObject.getSegment(), planeObject.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(planeObject));
- error("Invalid plane selector passed to kAddScreenItem");
+ error("kAddScreenItem: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(object));
}
ScreenItem *screenItem = plane->_screenItemList.findByObject(object);
@@ -272,53 +360,44 @@ void GfxFrameout::kernelUpdateScreenItem(const reg_t object) {
const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
Plane *plane = _planes.findByObject(planeObject);
if (plane == nullptr) {
- warning("screen item %x:%x (%s)", object.getSegment(), object.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(object));
- warning("plane %x:%x (%s)", planeObject.getSegment(), planeObject.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(planeObject));
- error("Invalid plane selector passed to kUpdateScreenItem");
+ error("kUpdateScreenItem: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(object));
}
ScreenItem *screenItem = plane->_screenItemList.findByObject(object);
if (screenItem == nullptr) {
- warning("screen item %x:%x (%s)", object.getSegment(), object.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(object));
- warning("plane %x:%x (%s)", planeObject.getSegment(), planeObject.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(planeObject));
- error("Invalid screen item passed to kUpdateScreenItem");
+ error("kUpdateScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(object), PRINT_REG(planeObject));
}
screenItem->update(object);
} else {
- warning("TODO: Magnifier view not implemented yet!");
+ error("Magnifier view is not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
}
}
void GfxFrameout::kernelDeleteScreenItem(const reg_t object) {
+ // The "fred" object is used to test graphics performance;
+ // it is impacted by framerate throttling, so disable the
+ // throttling when this item is on the screen for the
+ // performance check to pass.
+ if (!_benchmarkingFinished && checkForFred(object)) {
+ _benchmarkingFinished = true;
+ _throttleFrameOut = true;
+ }
+
_segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewInserted);
const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
Plane *plane = _planes.findByObject(planeObject);
if (plane == nullptr) {
- // TODO: Remove
-// warning("Invalid plane selector %04x:%04x passed to kDeleteScreenItem (real engine ignores this)", PRINT_REG(object));
return;
}
-// TODO: Remove
-// debug("Deleting screen item %04x:%04x from plane %04x:%04x", PRINT_REG(object), PRINT_REG(planeObject));
-
ScreenItem *screenItem = plane->_screenItemList.findByObject(object);
if (screenItem == nullptr) {
-// TODO: Remove
-// warning("Invalid screen item %04x:%04x passed to kDeleteScreenItem (real engine ignores this)", PRINT_REG(object));
return;
}
- if (screenItem->_created == 0) {
- screenItem->_created = 0;
- screenItem->_updated = 0;
- screenItem->_deleted = getScreenCount();
- } else {
- plane->_screenItemList.erase(screenItem);
- plane->_screenItemList.pack();
- }
+ deleteScreenItem(*screenItem, *plane);
}
#pragma mark -
@@ -338,8 +417,7 @@ void GfxFrameout::kernelAddPlane(const reg_t object) {
void GfxFrameout::kernelUpdatePlane(const reg_t object) {
Plane *plane = _planes.findByObject(object);
if (plane == nullptr) {
- warning("plane %x:%x (%s)", object.getSegment(), object.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(object));
- error("Invalid plane selector passed to kUpdatePlane");
+ error("kUpdatePlane: Plane %04x:%04x not found", PRINT_REG(object));
}
plane->update(object);
@@ -349,8 +427,7 @@ void GfxFrameout::kernelUpdatePlane(const reg_t object) {
void GfxFrameout::kernelDeletePlane(const reg_t object) {
Plane *plane = _planes.findByObject(object);
if (plane == nullptr) {
- warning("plane %x:%x (%s)", object.getSegment(), object.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(object));
- error("Invalid plane selector passed to kDeletePlane");
+ error("kDeletePlane: Plane %04x:%04x not found", PRINT_REG(object));
}
if (plane->_created) {
@@ -358,13 +435,53 @@ void GfxFrameout::kernelDeletePlane(const reg_t object) {
// just ends up doing this anyway so we skip the extra indirection
_planes.erase(plane);
} else {
- // TODO: Remove
-// debug("Deleting plane %04x:%04x", PRINT_REG(object));
plane->_created = 0;
plane->_deleted = g_sci->_gfxFrameout->getScreenCount();
}
}
+void GfxFrameout::deletePlane(Plane &planeToFind) {
+ Plane *plane = _planes.findByObject(planeToFind._object);
+ if (plane == nullptr) {
+ error("deletePlane: Plane %04x:%04x not found", PRINT_REG(planeToFind._object));
+ }
+
+ if (plane->_created) {
+ _planes.erase(plane);
+ } else {
+ plane->_created = 0;
+ plane->_moved = 0;
+ plane->_deleted = getScreenCount();
+ }
+}
+
+void GfxFrameout::kernelMovePlaneItems(const reg_t object, const int16 deltaX, const int16 deltaY, const bool scrollPics) {
+ Plane *plane = _planes.findByObject(object);
+ if (plane == nullptr) {
+ error("kMovePlaneItems: Plane %04x:%04x not found", PRINT_REG(object));
+ }
+
+ plane->scrollScreenItems(deltaX, deltaY, scrollPics);
+
+ for (ScreenItemList::iterator it = plane->_screenItemList.begin(); it != plane->_screenItemList.end(); ++it) {
+ ScreenItem &screenItem = **it;
+
+ // If object is a number, the screen item from the
+ // engine, not a script, and should be ignored
+ if (screenItem._object.isNumber()) {
+ continue;
+ }
+
+ if (deltaX != 0) {
+ writeSelectorValue(_segMan, screenItem._object, SELECTOR(x), readSelectorValue(_segMan, screenItem._object, SELECTOR(x)) + deltaX);
+ }
+
+ if (deltaY != 0) {
+ writeSelectorValue(_segMan, screenItem._object, SELECTOR(y), readSelectorValue(_segMan, screenItem._object, SELECTOR(y)) + deltaY);
+ }
+ }
+}
+
int16 GfxFrameout::kernelGetHighPlanePri() {
return _planes.getTopSciPlanePriority();
}
@@ -401,8 +518,7 @@ void GfxFrameout::updatePlane(Plane &plane) {
void GfxFrameout::kernelAddPicAt(const reg_t planeObject, const GuiResourceId pictureId, const int16 x, const int16 y, const bool mirrorX) {
Plane *plane = _planes.findByObject(planeObject);
if (plane == nullptr) {
- warning("plane %x:%x (%s)", planeObject.getSegment(), planeObject.getOffset(), g_sci->getEngineState()->_segMan->getObjectName(planeObject));
- error("Invalid plane selector passed to kAddPicAt");
+ error("kAddPicAt: Plane %04x:%04x not found", PRINT_REG(planeObject));
}
plane->addPic(pictureId, Common::Point(x, y), mirrorX);
}
@@ -410,7 +526,7 @@ void GfxFrameout::kernelAddPicAt(const reg_t planeObject, const GuiResourceId pi
#pragma mark -
#pragma mark Rendering
-void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &rect) {
+void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &eraseRect) {
// TODO: Robot
// if (_robot != nullptr) {
// _robot.doRobot();
@@ -424,12 +540,11 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &rect)
screenItemLists.resize(_planes.size());
eraseLists.resize(_planes.size());
- // _numActiveRemaps was a global in SCI engine
- if (/* TODO Remap::_numActiveRemaps > 0 */ false && _remapOccurred) {
- // remapMarkRedraw();
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
}
- calcLists(screenItemLists, eraseLists, rect);
+ calcLists(screenItemLists, eraseLists, eraseRect);
for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
list->sort();
@@ -458,7 +573,7 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &rect)
// _robot->frameAlmostVisible();
// }
- _palette->updateHardware();
+ _palette->updateHardware(!shouldShowBits);
if (shouldShowBits) {
showBits();
@@ -472,130 +587,221 @@ void GfxFrameout::frameOut(const bool shouldShowBits, const Common::Rect &rect)
// }
}
-// Determine the parts of 'r' that aren't overlapped by 'other'.
-// Returns -1 if r and other have no intersection.
-// Returns number of returned parts (in outRects) otherwise.
-// (In particular, this returns 0 if r is contained in other.)
+/**
+ * Determines the parts of `r` that aren't overlapped by `other`.
+ * Returns -1 if `r` and `other` have no intersection.
+ * Returns number of returned parts (in `outRects`) otherwise.
+ * (In particular, this returns 0 if `r` is contained in `other`.)
+ */
int splitRects(Common::Rect r, const Common::Rect &other, Common::Rect(&outRects)[4]) {
if (!r.intersects(other)) {
return -1;
}
- int count = 0;
+ int splitCount = 0;
if (r.top < other.top) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.bottom = other.top;
r.top = other.top;
}
if (r.bottom > other.bottom) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.top = other.bottom;
r.bottom = other.bottom;
}
if (r.left < other.left) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.right = other.left;
r.left = other.left;
}
if (r.right > other.right) {
- Common::Rect &t = outRects[count++];
+ Common::Rect &t = outRects[splitCount++];
t = r;
t.left = other.right;
}
- return count;
+ return splitCount;
}
-void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &calcRect) {
- RectList rectlist;
- Common::Rect outRects[4];
+/**
+ * Determines the parts of `middleRect` that aren't overlapped
+ * by `showRect`, optimised for contiguous memory writes.
+ * Returns -1 if `middleRect` and `showRect` have no intersection.
+ * Returns number of returned parts (in `outRects`) otherwise.
+ * (In particular, this returns 0 if `middleRect` is contained
+ * in `other`.)
+ *
+ * `middleRect` is modified directly to extend into the upper
+ * and lower rects.
+ */
+int splitRectsForRender(Common::Rect &middleRect, const Common::Rect &showRect, Common::Rect(&outRects)[2]) {
+ if (!middleRect.intersects(showRect)) {
+ return -1;
+ }
+
+ const int16 minLeft = MIN(middleRect.left, showRect.left);
+ const int16 maxRight = MAX(middleRect.right, showRect.right);
+ int16 upperLeft, upperTop, upperRight, upperMaxTop;
+ if (middleRect.top < showRect.top) {
+ upperLeft = middleRect.left;
+ upperTop = middleRect.top;
+ upperRight = middleRect.right;
+ upperMaxTop = showRect.top;
+ }
+ else {
+ upperLeft = showRect.left;
+ upperTop = showRect.top;
+ upperRight = showRect.right;
+ upperMaxTop = middleRect.top;
+ }
+
+ int16 lowerLeft, lowerRight, lowerBottom, lowerMinBottom;
+ if (middleRect.bottom > showRect.bottom) {
+ lowerLeft = middleRect.left;
+ lowerRight = middleRect.right;
+ lowerBottom = middleRect.bottom;
+ lowerMinBottom = showRect.bottom;
+ } else {
+ lowerLeft = showRect.left;
+ lowerRight = showRect.right;
+ lowerBottom = showRect.bottom;
+ lowerMinBottom = middleRect.bottom;
+ }
+
+ int splitCount = 0;
+ middleRect.left = minLeft;
+ middleRect.top = upperMaxTop;
+ middleRect.right = maxRight;
+ middleRect.bottom = lowerMinBottom;
+
+ if (upperTop != upperMaxTop) {
+ Common::Rect &upperRect = outRects[0];
+ upperRect.left = upperLeft;
+ upperRect.top = upperTop;
+ upperRect.right = upperRight;
+ upperRect.bottom = upperMaxTop;
+
+ // Merge upper rect into middle rect if possible
+ if (upperRect.left == middleRect.left && upperRect.right == middleRect.right) {
+ middleRect.top = upperRect.top;
+ } else {
+ ++splitCount;
+ }
+ }
+
+ if (lowerBottom != lowerMinBottom) {
+ Common::Rect &lowerRect = outRects[splitCount];
+ lowerRect.left = lowerLeft;
+ lowerRect.top = lowerMinBottom;
+ lowerRect.right = lowerRight;
+ lowerRect.bottom = lowerBottom;
+
+ // Merge lower rect into middle rect if possible
+ if (lowerRect.left == middleRect.left && lowerRect.right == middleRect.right) {
+ middleRect.bottom = lowerRect.bottom;
+ } else {
+ ++splitCount;
+ }
+ }
+
+ assert(splitCount <= 2);
+ return splitCount;
+}
+
+// NOTE: The third rectangle parameter is only ever given a non-empty rect
+// by VMD code, via `frameOut`
+void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &eraseRect) {
+ RectList eraseList;
+ Common::Rect outRects[4];
int deletedPlaneCount = 0;
- bool addedToRectList = false;
- int planeCount = _planes.size();
+ bool addedToEraseList = false;
bool foundTransparentPlane = false;
- if (!calcRect.isEmpty()) {
- addedToRectList = true;
- rectlist.add(calcRect);
+ if (!eraseRect.isEmpty()) {
+ addedToEraseList = true;
+ eraseList.add(eraseRect);
}
- for (int outerPlaneIndex = 0; outerPlaneIndex < planeCount; ++outerPlaneIndex) {
- Plane *outerPlane = _planes[outerPlaneIndex];
+ PlaneList::size_type planeCount = _planes.size();
+ for (PlaneList::size_type outerPlaneIndex = 0; outerPlaneIndex < planeCount; ++outerPlaneIndex) {
+ const Plane *outerPlane = _planes[outerPlaneIndex];
+ const Plane *visiblePlane = _visiblePlanes.findByObject(outerPlane->_object);
+ // NOTE: SSCI only ever checks for kPlaneTypeTransparent here, even
+ // though kPlaneTypeTransparentPicture is also a transparent plane
if (outerPlane->_type == kPlaneTypeTransparent) {
foundTransparentPlane = true;
}
- Plane *visiblePlane = _visiblePlanes.findByObject(outerPlane->_object);
-
if (outerPlane->_deleted) {
- if (visiblePlane != nullptr) {
- if (!visiblePlane->_screenRect.isEmpty()) {
- addedToRectList = true;
- rectlist.add(visiblePlane->_screenRect);
- }
+ if (visiblePlane != nullptr && !visiblePlane->_screenRect.isEmpty()) {
+ eraseList.add(visiblePlane->_screenRect);
+ addedToEraseList = true;
}
++deletedPlaneCount;
- } else if (visiblePlane != nullptr) {
- if (outerPlane->_updated) {
- --outerPlane->_updated;
-
- int splitcount = splitRects(visiblePlane->_screenRect, outerPlane->_screenRect, outRects);
- if (splitcount) {
- if (splitcount == -1) {
- if (!visiblePlane->_screenRect.isEmpty()) {
- rectlist.add(visiblePlane->_screenRect);
- }
+ } else if (visiblePlane != nullptr && outerPlane->_moved) {
+ // _moved will be decremented in the final loop through the planes,
+ // at the end of this function
+
+ {
+ const int splitCount = splitRects(visiblePlane->_screenRect, outerPlane->_screenRect, outRects);
+ if (splitCount) {
+ if (splitCount == -1 && !visiblePlane->_screenRect.isEmpty()) {
+ eraseList.add(visiblePlane->_screenRect);
} else {
- for (int i = 0; i < splitcount; ++i) {
- rectlist.add(outRects[i]);
+ for (int i = 0; i < splitCount; ++i) {
+ eraseList.add(outRects[i]);
}
}
-
- addedToRectList = true;
+ addedToEraseList = true;
}
+ }
- if (!outerPlane->_redrawAllCount) {
- int splitCount = splitRects(outerPlane->_screenRect, visiblePlane->_screenRect, outRects);
- if (splitCount) {
- for (int i = 0; i < splitCount; ++i) {
- rectlist.add(outRects[i]);
- }
- addedToRectList = true;
+ if (!outerPlane->_redrawAllCount) {
+ const int splitCount = splitRects(outerPlane->_screenRect, visiblePlane->_screenRect, outRects);
+ if (splitCount) {
+ for (int i = 0; i < splitCount; ++i) {
+ eraseList.add(outRects[i]);
}
+ addedToEraseList = true;
}
}
}
- if (addedToRectList) {
- for (RectList::iterator rect = rectlist.begin(); rect != rectlist.end(); ++rect) {
- for (int innerPlaneIndex = _planes.size() - 1; innerPlaneIndex >= 0; --innerPlaneIndex) {
- Plane *innerPlane = _planes[innerPlaneIndex];
-
- if (!innerPlane->_deleted && innerPlane->_type != kPlaneTypeTransparent && innerPlane->_screenRect.intersects(**rect)) {
- if (innerPlane->_redrawAllCount == 0) {
- eraseLists[innerPlaneIndex].add(innerPlane->_screenRect.findIntersectingRect(**rect));
+ if (addedToEraseList) {
+ for (RectList::size_type rectIndex = 0; rectIndex < eraseList.size(); ++rectIndex) {
+ const Common::Rect &rect = *eraseList[rectIndex];
+ for (int innerPlaneIndex = planeCount - 1; innerPlaneIndex >= 0; --innerPlaneIndex) {
+ const Plane &innerPlane = *_planes[innerPlaneIndex];
+
+ if (
+ !innerPlane._deleted &&
+ innerPlane._type != kPlaneTypeTransparent &&
+ innerPlane._screenRect.intersects(rect)
+ ) {
+ if (!innerPlane._redrawAllCount) {
+ eraseLists[innerPlaneIndex].add(innerPlane._screenRect.findIntersectingRect(rect));
}
- int splitCount = splitRects(**rect, innerPlane->_screenRect, outRects);
+ const int splitCount = splitRects(rect, innerPlane._screenRect, outRects);
for (int i = 0; i < splitCount; ++i) {
- rectlist.add(outRects[i]);
+ eraseList.add(outRects[i]);
}
- rectlist.erase(rect);
+ eraseList.erase_at(rectIndex);
break;
}
}
}
- rectlist.pack();
+ eraseList.pack();
}
}
@@ -607,9 +813,9 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
if (plane->_deleted) {
--plane->_deleted;
if (plane->_deleted <= 0) {
- PlaneList::iterator visiblePlaneIt = Common::find_if(_visiblePlanes.begin(), _visiblePlanes.end(), FindByObject<Plane *>(plane->_object));
- if (visiblePlaneIt != _visiblePlanes.end()) {
- _visiblePlanes.erase(visiblePlaneIt);
+ const int visiblePlaneIndex = _visiblePlanes.findIndexByObject(plane->_object);
+ if (visiblePlaneIndex != -1) {
+ _visiblePlanes.remove_at(visiblePlaneIndex);
}
_planes.remove_at(planeIndex);
@@ -624,103 +830,114 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
}
}
+ // Some planes may have been deleted, so re-retrieve count
planeCount = _planes.size();
- for (int outerIndex = 0; outerIndex < planeCount; ++outerIndex) {
- // "outer" just refers to the outer loop
- Plane *outerPlane = _planes[outerIndex];
- if (outerPlane->_priorityChanged) {
- --outerPlane->_priorityChanged;
- Plane *visibleOuterPlane = _visiblePlanes.findByObject(outerPlane->_object);
+ for (PlaneList::size_type outerIndex = 0; outerIndex < planeCount; ++outerIndex) {
+ // "outer" just refers to the outer loop
+ Plane &outerPlane = *_planes[outerIndex];
+ if (outerPlane._priorityChanged) {
+ --outerPlane._priorityChanged;
+
+ const Plane *visibleOuterPlane = _visiblePlanes.findByObject(outerPlane._object);
+ if (visibleOuterPlane == nullptr) {
+ warning("calcLists could not find visible plane for %04x:%04x", PRINT_REG(outerPlane._object));
+ continue;
+ }
- rectlist.add(outerPlane->_screenRect.findIntersectingRect(visibleOuterPlane->_screenRect));
+ eraseList.add(outerPlane._screenRect.findIntersectingRect(visibleOuterPlane->_screenRect));
- for (int innerIndex = planeCount - 1; innerIndex >= 0; --innerIndex) {
+ for (int innerIndex = (int)planeCount - 1; innerIndex >= 0; --innerIndex) {
// "inner" just refers to the inner loop
- Plane *innerPlane = _planes[innerIndex];
- Plane *visibleInnerPlane = _visiblePlanes.findByObject(innerPlane->_object);
-
- int rectCount = rectlist.size();
- for (int rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
- int splitCount = splitRects(*rectlist[rectIndex], _planes[innerIndex]->_screenRect, outRects);
+ const Plane &innerPlane = *_planes[innerIndex];
+ const Plane *visibleInnerPlane = _visiblePlanes.findByObject(innerPlane._object);
+ const RectList::size_type rectCount = eraseList.size();
+ for (RectList::size_type rectIndex = 0; rectIndex < rectCount; ++rectIndex) {
+ const int splitCount = splitRects(*eraseList[rectIndex], innerPlane._screenRect, outRects);
if (splitCount == 0) {
if (visibleInnerPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
- if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
- if (outerPlane->_priority <= innerPlane->_priority) {
- eraseLists[innerIndex].add(*rectlist[rectIndex]);
+ if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane._priority - innerPlane._priority) <= 0) {
+ if (outerPlane._priority <= innerPlane._priority) {
+ eraseLists[innerIndex].add(*eraseList[rectIndex]);
} else {
- eraseLists[outerIndex].add(*rectlist[rectIndex]);
+ eraseLists[outerIndex].add(*eraseList[rectIndex]);
}
}
}
- rectlist.erase_at(rectIndex);
+ eraseList.erase_at(rectIndex);
} else if (splitCount != -1) {
for (int i = 0; i < splitCount; ++i) {
- rectlist.add(outRects[i]);
+ eraseList.add(outRects[i]);
}
if (visibleInnerPlane != nullptr) {
// same priority, or relative priority between inner/outer changed
- if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane->_priority - innerPlane->_priority) <= 0) {
- *rectlist[rectIndex] = outerPlane->_screenRect.findIntersectingRect(innerPlane->_screenRect);
- if (outerPlane->_priority <= innerPlane->_priority) {
- eraseLists[innerIndex].add(*rectlist[rectIndex]);
- }
- else {
- eraseLists[outerIndex].add(*rectlist[rectIndex]);
+ if ((visibleOuterPlane->_priority - visibleInnerPlane->_priority) * (outerPlane._priority - innerPlane._priority) <= 0) {
+ *eraseList[rectIndex] = outerPlane._screenRect.findIntersectingRect(innerPlane._screenRect);
+
+ if (outerPlane._priority <= innerPlane._priority) {
+ eraseLists[innerIndex].add(*eraseList[rectIndex]);
+ } else {
+ eraseLists[outerIndex].add(*eraseList[rectIndex]);
}
}
}
- rectlist.erase_at(rectIndex);
+ eraseList.erase_at(rectIndex);
}
}
- rectlist.pack();
+ eraseList.pack();
}
}
}
- for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
- Plane *plane = _planes[planeIndex];
- Plane *visiblePlane = nullptr;
+ for (PlaneList::size_type planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
+ Plane &plane = *_planes[planeIndex];
+ Plane *visiblePlane = _visiblePlanes.findByObject(plane._object);
- PlaneList::iterator visiblePlaneIt = Common::find_if(_visiblePlanes.begin(), _visiblePlanes.end(), FindByObject<Plane *>(plane->_object));
- if (visiblePlaneIt != _visiblePlanes.end()) {
- visiblePlane = *visiblePlaneIt;
- }
+ if (!plane._screenRect.isEmpty()) {
+ if (plane._redrawAllCount) {
+ plane.redrawAll(visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
+ } else {
+ if (visiblePlane == nullptr) {
+ error("Missing visible plane for source plane %04x:%04x", PRINT_REG(plane._object));
+ }
- if (plane->_redrawAllCount) {
- plane->redrawAll(visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
- } else {
- if (visiblePlane == nullptr) {
- error("Missing visible plane for source plane %04x:%04x", PRINT_REG(plane->_object));
+ plane.calcLists(*visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
}
+ } else {
+ plane.decrementScreenItemArrayCounts(visiblePlane, false);
+ }
- plane->calcLists(*visiblePlane, _planes, drawLists[planeIndex], eraseLists[planeIndex]);
+ if (plane._moved) {
+ // the work for handling moved/resized planes was already done
+ // earlier in the function, we are just cleaning up now
+ --plane._moved;
}
- if (plane->_created) {
- _visiblePlanes.add(new Plane(*plane));
- --plane->_created;
- } else if (plane->_moved) {
- assert(visiblePlaneIt != _visiblePlanes.end());
- **visiblePlaneIt = *plane;
- --plane->_moved;
+ if (plane._created) {
+ _visiblePlanes.add(new Plane(plane));
+ --plane._created;
+ } else if (plane._updated) {
+ *visiblePlane = plane;
+ --plane._updated;
}
}
+ // NOTE: SSCI only looks for kPlaneTypeTransparent, not
+ // kPlaneTypeTransparentPicture
if (foundTransparentPlane) {
- for (int planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
- for (int i = planeIndex + 1; i < planeCount; ++i) {
+ for (PlaneList::size_type planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
+ for (PlaneList::size_type i = planeIndex + 1; i < planeCount; ++i) {
if (_planes[i]->_type == kPlaneTypeTransparent) {
_planes[i]->filterUpEraseRects(drawLists[i], eraseLists[planeIndex]);
}
}
if (_planes[planeIndex]->_type == kPlaneTypeTransparent) {
- for (int i = planeIndex - 1; i >= 0; --i) {
+ for (int i = (int)planeIndex - 1; i >= 0; --i) {
_planes[i]->filterDownEraseRects(drawLists[i], eraseLists[i], eraseLists[planeIndex]);
}
@@ -729,7 +946,7 @@ void GfxFrameout::calcLists(ScreenItemListList &drawLists, EraseListList &eraseL
}
}
- for (int i = planeIndex + 1; i < planeCount; ++i) {
+ for (PlaneList::size_type i = planeIndex + 1; i < planeCount; ++i) {
if (_planes[i]->_type == kPlaneTypeTransparent) {
_planes[i]->filterUpDrawRects(drawLists[i], drawLists[planeIndex]);
}
@@ -743,77 +960,94 @@ void GfxFrameout::drawEraseList(const RectList &eraseList, const Plane &plane) {
return;
}
- for (RectList::const_iterator it = eraseList.begin(); it != eraseList.end(); ++it) {
- mergeToShowList(**it, _showList, _overdrawThreshold);
- _currentBuffer.fillRect(**it, plane._back);
+ const RectList::size_type eraseListSize = eraseList.size();
+ for (RectList::size_type i = 0; i < eraseListSize; ++i) {
+ mergeToShowList(*eraseList[i], _showList, _overdrawThreshold);
+ _currentBuffer.fillRect(*eraseList[i], plane._back);
}
}
void GfxFrameout::drawScreenItemList(const DrawList &screenItemList) {
- _hasRemappedScreenItem = false;
- if (/* TODO: g_Remap_UnknownCounter2 */ false && !_priorityMap.isNull()) {
- for (DrawList::const_iterator it = screenItemList.begin(); it != screenItemList.end(); ++it) {
- if ((*it)->screenItem->getCelObj()._remap) {
- _hasRemappedScreenItem = true;
- break;
- }
- }
- }
-
- for (DrawList::const_iterator it = screenItemList.begin(); it != screenItemList.end(); ++it) {
- DrawItem &drawItem = **it;
+ const DrawList::size_type drawListSize = screenItemList.size();
+ for (DrawList::size_type i = 0; i < drawListSize; ++i) {
+ const DrawItem &drawItem = *screenItemList[i];
mergeToShowList(drawItem.rect, _showList, _overdrawThreshold);
- ScreenItem &screenItem = *drawItem.screenItem;
+ const ScreenItem &screenItem = *drawItem.screenItem;
// TODO: Remove
-// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), drawItem.rect.left, drawItem.rect.top, drawItem.rect.right, drawItem.rect.bottom);
+// debug("Drawing item %04x:%04x to %d %d %d %d", PRINT_REG(screenItem._object), PRINT_RECT(drawItem.rect));
CelObj &celObj = *screenItem._celObj;
celObj.draw(_currentBuffer, screenItem, drawItem.rect, screenItem._mirrorX ^ celObj._mirrorX);
}
}
void GfxFrameout::mergeToShowList(const Common::Rect &drawRect, RectList &showList, const int overdrawThreshold) {
- Common::Rect merged(drawRect);
-
- bool didDelete = true;
- RectList::size_type count = showList.size();
- while (didDelete && count) {
- didDelete = false;
-
- for (RectList::size_type i = 0; i < count; ++i) {
- Common::Rect existing = *showList[i];
- Common::Rect candidate;
- candidate.left = MIN(merged.left, existing.left);
- candidate.top = MIN(merged.top, existing.top);
- candidate.right = MAX(merged.right, existing.right);
- candidate.bottom = MAX(merged.bottom, existing.bottom);
-
- if (candidate.height() * candidate.width() - merged.width() * merged.height() - existing.width() * existing.height() <= overdrawThreshold) {
- merged = candidate;
- showList.erase_at(i);
- didDelete = true;
+ RectList mergeList;
+ Common::Rect merged;
+ mergeList.add(drawRect);
+
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ bool didMerge = false;
+ const Common::Rect &r1 = *mergeList[i];
+ if (!r1.isEmpty()) {
+ for (RectList::size_type j = 0; j < showList.size(); ++j) {
+ const Common::Rect &r2 = *showList[j];
+ if (!r2.isEmpty()) {
+ merged = r1;
+ merged.extend(r2);
+
+ int difference = merged.width() * merged.height();
+ difference -= r1.width() * r1.height();
+ difference -= r2.width() * r2.height();
+ if (r1.intersects(r2)) {
+ const Common::Rect overlap = r1.findIntersectingRect(r2);
+ difference += overlap.width() * overlap.height();
+ }
+
+ if (difference <= overdrawThreshold) {
+ mergeList.erase_at(i);
+ showList.erase_at(j);
+ mergeList.add(merged);
+ didMerge = true;
+ break;
+ } else {
+ Common::Rect outRects[2];
+ int splitCount = splitRectsForRender(*mergeList[i], *showList[j], outRects);
+ if (splitCount != -1) {
+ mergeList.add(*mergeList[i]);
+ mergeList.erase_at(i);
+ showList.erase_at(j);
+ didMerge = true;
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
+ }
+ break;
+ }
+ }
+ }
}
- }
- count = showList.pack();
+ if (didMerge) {
+ showList.pack();
+ }
+ }
}
- showList.add(merged);
+ mergeList.pack();
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ showList.add(*mergeList[i]);
+ }
}
void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry *showStyle) {
- Palette sourcePalette(*_palette->getNextPalette());
+ Palette sourcePalette(_palette->getNextPalette());
alterVmap(sourcePalette, sourcePalette, -1, styleRanges);
- // TODO: unsure if this is what this variable actually
- // represents, but it is the correct variable number
- int16 lastRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
+ int16 prevRoom = g_sci->getEngineState()->variables[VAR_GLOBAL][12].toSint16();
Common::Rect rect(_screen->getDisplayWidth(), _screen->getDisplayHeight());
_showList.add(rect);
showBits();
- Common::Rect calcRect(0, 0);
-
// NOTE: The original engine allocated these as static arrays of 100
// pointers to ScreenItemList / RectList
ScreenItemListList screenItemLists;
@@ -822,13 +1056,11 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
screenItemLists.resize(_planes.size());
eraseLists.resize(_planes.size());
- // TODO: Remap
- // _numActiveRemaps was a global in SCI engine
- // if (Remap::_numActiveRemaps > 0 && _remapOccurred) {
- // _screen->remapMarkRedraw();
- // }
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
- calcLists(screenItemLists, eraseLists, calcRect);
+ calcLists(screenItemLists, eraseLists);
for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
list->sort();
}
@@ -847,9 +1079,9 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
drawScreenItemList(screenItemLists[i]);
}
- Palette nextPalette(*_palette->getNextPalette());
+ Palette nextPalette(_palette->getNextPalette());
- if (lastRoom < 1000) {
+ if (prevRoom < 1000) {
for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
if (styleRanges[i] == -1 || styleRanges[i] == 0) {
sourcePalette.colors[i] = nextPalette.colors[i];
@@ -858,6 +1090,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
}
} else {
for (int i = 0; i < ARRAYSIZE(sourcePalette.colors); ++i) {
+ // TODO: Limiting range 72 to 103 is NOT present in every game
if (styleRanges[i] == -1 || (styleRanges[i] == 0 && i > 71 && i < 104)) {
sourcePalette.colors[i] = nextPalette.colors[i];
sourcePalette.colors[i].used = true;
@@ -873,7 +1106,7 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
if (showStyle && showStyle->type != kShowStyleUnknown) {
// TODO: SCI2.1mid transition effects
// processEffects();
- warning("Transition not implemented!");
+ warning("Transition %d not implemented!", showStyle->type);
} else {
showBits();
}
@@ -881,17 +1114,14 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
_frameNowVisible = true;
for (PlaneList::iterator plane = _planes.begin(); plane != _planes.end(); ++plane) {
-// TODO:
-// plane->updateRedrawAllCount();
+ (*plane)->_redrawAllCount = getScreenCount();
}
- // TODO: Remap
- // _numActiveRemaps was a global in SCI engine
- // if (Remap::_numActiveRemaps > 0 && _remapOccurred) {
- // _screen->remapMarkRedraw();
- // }
+ if (g_sci->_gfxRemap32->getRemapCount() > 0 && _remapOccurred) {
+ remapMarkRedraw();
+ }
- calcLists(screenItemLists, eraseLists, calcRect);
+ calcLists(screenItemLists, eraseLists);
for (ScreenItemListList::iterator list = screenItemLists.begin(); list != screenItemLists.end(); ++list) {
list->sort();
}
@@ -914,16 +1144,12 @@ void GfxFrameout::palMorphFrameOut(const int8 *styleRanges, const ShowStyleEntry
_palette->submit(nextPalette);
_palette->updateFFrame();
- _palette->updateHardware();
+ _palette->updateHardware(false);
showBits();
_frameNowVisible = true;
}
-// TODO: What does the bit masking for the show rects do,
-// and does it cause an off-by-one error in rect calculations
-// since SOL_Rect is BR inclusive and Common::Rect is BR
-// exclusive?
void GfxFrameout::showBits() {
for (RectList::const_iterator rect = _showList.begin(); rect != _showList.end(); ++rect) {
Common::Rect rounded(**rect);
@@ -969,7 +1195,7 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
if (styleRanges[paletteIndex] == style) {
int minDiff = 262140;
- int minDiffIndex;
+ int minDiffIndex = paletteIndex;
for (int i = 0; i < 236; ++i) {
if (styleRanges[i] != style) {
@@ -989,7 +1215,7 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
if (style == 1 && styleRanges[paletteIndex] == 0) {
int minDiff = 262140;
- int minDiffIndex;
+ int minDiffIndex = paletteIndex;
for (int i = 0; i < 236; ++i) {
int r = palette2.colors[i].r;
@@ -1010,14 +1236,15 @@ void GfxFrameout::alterVmap(const Palette &palette1, const Palette &palette2, co
// NOTE: This is currBuffer->ptr in SCI engine
byte *pixels = (byte *)_currentBuffer.getPixels();
- // TODO: Guessing that display width/height is the correct
- // equivalent to screen width/height in SCI engine
for (int pixelIndex = 0, numPixels = _currentBuffer.screenWidth * _currentBuffer.screenHeight; pixelIndex < numPixels; ++pixelIndex) {
byte currentValue = pixels[pixelIndex];
int8 styleRangeValue = styleRanges[currentValue];
if (styleRangeValue == -1 && styleRangeValue == style) {
currentValue = pixels[pixelIndex] = clut[currentValue];
- styleRangeValue = styleRanges[clut[currentValue]];
+ // NOTE: In original engine this assignment happens outside of the
+ // condition, but if the branch is not followed the value is just
+ // going to be the same as it was before
+ styleRangeValue = styleRanges[currentValue];
}
if (
@@ -1068,44 +1295,7 @@ inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *cons
lastEntry->next = showStyle->next;
}
- // NOTE: Differences from SCI2/2.1early engine:
- // 1. Memory of ShowStyle-owned objects was freed before ShowStyle was
- // removed from the linked list, but since this operation is position
- // independent, it has been moved after removal from the list for
- // consistency with SCI2.1mid+
- // 2. In SCI2, `screenItems` was a pointer to an array of pointers, so
- // extra deletes were performed here; we use an owned container object
- // instead, which is automatically freed when ShowStyle is freed
-#if 0
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- uint8 type = showStyle->type;
-
- if (type >= 1 && type <= 10) {
- ScreenItemList &styleItems = showStyle->screenItems;
- for (ScreenItemList::iterator it = styleItems.begin(); it != styleItems.end(); ++it) {
- if (active) {
- // TODO: _screen->deleteScreenItem(showStyle->plane, *it->id);
- _screenItems.remove(*it);
- }
- delete *it;
- }
- } else if (type == 11 || type == 12) {
- if (!showStyle->bitmapMemId.isNull()) {
- _segMan->freeHunkEntry(showStyle->bitmapMemId);
- }
- if (showStyle->bitmapScreenItem != nullptr) {
- // TODO: _screen->deleteScreenItem(showStyle->plane, showStyle->bitmapScreenItem->id);
- _screenItems.remove(showStyle->bitmapScreenItem);
- delete showStyle->bitmapScreenItem;
- }
- }
- } else {
-#endif
- delete[] showStyle->fadeColorRanges;
-#if 0
- }
-#endif
-
+ delete[] showStyle->fadeColorRanges;
delete showStyle;
// TODO: Verify that this is the correct entry to return
@@ -1117,11 +1307,20 @@ inline ShowStyleEntry *GfxFrameout::deleteShowStyleInternal(ShowStyleEntry *cons
// and need to be fixed in future
// TODO: SQ6 does not use 'priority' (exists since SCI2) or 'blackScreen' (exists since SCI3);
// check to see if other versions use or if they are just always ignored
-void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, const reg_t &pFadeArray, const int16 divisions, const int16 blackScreen) {
+void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 back, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen) {
bool hasDivisions = false;
bool hasFadeArray = false;
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+
+ // KQ7 2.0b uses a mismatched version of the Styler script (SCI2.1early script
+ // for SCI2.1mid engine), so the calls it makes to kSetShowStyle are wrong and
+ // put `divisions` where `pFadeArray` is supposed to be
+ if (getSciVersion() == SCI_VERSION_2_1_MIDDLE && g_sci->getGameId() == GID_KQ7) {
+ hasDivisions = argc > 7;
+ hasFadeArray = false;
+ divisions = argc > 7 ? pFadeArray.toSint16() : -1;
+ pFadeArray = NULL_REG;
+ } else if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
hasDivisions = argc > 7;
hasFadeArray = false;
} else if (getSciVersion() < SCI_VERSION_3) {
@@ -1151,20 +1350,12 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
error("Plane %04x:%04x is not present in active planes list", PRINT_REG(planeObj));
}
- // TODO: This is Plane.gameRect in SCI engine, not planeRect. Engine uses
- // Plane::ConvGameRectToPlaneRect to convert from gameRect to planeRect.
- // Also this never gets used by SQ6 so it is not clear what it does yet
- // Common::Rect gameRect = plane.planeRect;
-
bool createNewEntry = true;
ShowStyleEntry *entry = findShowStyleForPlane(planeObj);
if (entry != nullptr) {
+ // TODO: SCI2.1early has different criteria for show style reuse
bool useExisting = true;
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- useExisting = plane->_planeRect.width() == entry->width && plane->_planeRect.height() == entry->height;
- }
-
if (useExisting) {
useExisting = entry->divisions == (hasDivisions ? divisions : _defaultDivisions[type]) && entry->unknownC == _defaultUnknownC[type];
}
@@ -1193,39 +1384,28 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
entry->divisions = hasDivisions ? divisions : _defaultDivisions[type];
entry->plane = planeObj;
-#if 0
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- entry->bitmapMemId = NULL_REG;
- entry->screenItems.empty();
- entry->width = plane->_planeRect.width();
- entry->height = plane->_planeRect.height();
- } else {
-#endif
- entry->fadeColorRanges = nullptr;
- if (hasFadeArray) {
- // NOTE: SCI2.1mid engine does no check to verify that an array is
- // successfully retrieved, and SegMan will cause a fatal error
- // if we try to use a memory segment that is not an array
- SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
-
- uint32 rangeCount = table->getSize();
- entry->fadeColorRangesCount = rangeCount;
-
- // NOTE: SCI engine code always allocates memory even if the range
- // table has no entries, but this does not really make sense, so
- // we avoid the allocation call in this case
- if (rangeCount > 0) {
- entry->fadeColorRanges = new uint16[rangeCount];
- for (size_t i = 0; i < rangeCount; ++i) {
- entry->fadeColorRanges[i] = table->getValue(i).toUint16();
- }
+ entry->fadeColorRanges = nullptr;
+ if (hasFadeArray) {
+ // NOTE: SCI2.1mid engine does no check to verify that an array is
+ // successfully retrieved, and SegMan will cause a fatal error
+ // if we try to use a memory segment that is not an array
+ SciArray<reg_t> *table = _segMan->lookupArray(pFadeArray);
+
+ uint32 rangeCount = table->getSize();
+ entry->fadeColorRangesCount = rangeCount;
+
+ // NOTE: SCI engine code always allocates memory even if the range
+ // table has no entries, but this does not really make sense, so
+ // we avoid the allocation call in this case
+ if (rangeCount > 0) {
+ entry->fadeColorRanges = new uint16[rangeCount];
+ for (size_t i = 0; i < rangeCount; ++i) {
+ entry->fadeColorRanges[i] = table->getValue(i).toUint16();
}
- } else {
- entry->fadeColorRangesCount = 0;
}
-#if 0
+ } else {
+ entry->fadeColorRangesCount = 0;
}
-#endif
}
// NOTE: The original engine had no nullptr check and would just crash
@@ -1242,9 +1422,6 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
entry->delay = (seconds * 60 + entry->divisions - 1) / entry->divisions;
if (entry->delay == 0) {
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE && entry->fadeColorRanges != nullptr) {
-#endif
if (entry->fadeColorRanges != nullptr) {
delete[] entry->fadeColorRanges;
}
@@ -1258,235 +1435,13 @@ void GfxFrameout::kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, c
}
if (createNewEntry) {
- // TODO: Implement SCI3, which may or may not actually have
- // the same transitions as SCI2/SCI2.1early, but implemented
- // differently
-#if 0
- if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
- switch (entry->type) {
- case kShowStyleHShutterIn:
- case kShowStyleHShutterOut:
- prepareShowStyleWipe(entry, priority, 2, true);
- break;
-
- case kShowStyleVShutterIn:
- case kShowStyleVShutterOut:
- prepareShowStyleWipe(entry, priority, 2, false);
- break;
-
- case kShowStyleHWipe1:
- case kShowStyleHWipe2:
- prepareShowStyleWipe(entry, priority, 1, true);
- break;
-
- case kShowStyleVWipe1:
- case kShowStyleVWipe2:
- prepareShowStyleWipe(entry, priority, 1, false);
- break;
-
- case kShowStyleIrisIn:
- case kShowStyleIrisOut:
- prepareShowStyleIris(entry, priority);
- break;
-
- case kShowStyle11:
- case kShowStyle12:
- prepareShowStylePixels(entry, priority, plane->planeRect);
- break;
-
- default:
- break;
- }
- }
-#endif
-
+ // TODO: Implement SCI2.1early and SCI3
entry->next = _showStyles;
_showStyles = entry;
}
}
}
-#if 0
-void addFrameoutEntryInternal(ShowStyleEntry *const showStyle, const int16 priority, const CelInfo32 &celInfo, const Common::Rect &rect) {
- ScreenItem *screenItem = new ScreenItem;
- screenItem->plane = showStyle->plane;
- screenItem->celInfo = celInfo;
- screenItem->celRect = rect;
- screenItem->isInList = true;
- screenItem->priority = priority;
- screenItem->visible = true;
- showStyle->screenItems.push_back(screenItem);
-}
-
-void GfxFrameout::prepareShowStyleWipe(ShowStyleEntry *const showStyle, const int16 priority, const int16 edgeCount, const bool horizontal) {
- assert(edgeCount == 1 || edgeCount == 2);
-
- const int numScreenItems = showStyle->divisions * edgeCount;
- const int extra = edgeCount > 1 ? 1 : 0;
-
- showStyle->edgeCount = edgeCount;
- showStyle->screenItems.reserve(numScreenItems);
-
- CelInfo32 celInfo;
- celInfo.bitmap = NULL_REG;
- celInfo.type = kCelObjTypeView;
- celInfo.color = showStyle->color;
-
- for (int i = 0; i < numScreenItems; ++i) {
- Common::Rect rect;
-
- if (horizontal) {
- rect.top = 0;
- rect.bottom = showStyle->height - 1;
- rect.left = (showStyle->width * i) / (showStyle->divisions * edgeCount);
- rect.right = ((i + 1) * (showStyle->width + extra)) / (showStyle->divisions * edgeCount) - 1;
- } else {
- rect.left = 0;
- rect.right = showStyle->width - 1;
- rect.top = (showStyle->height * i) / (showStyle->divisions * edgeCount);
- rect.bottom = ((i + 1) * (showStyle->height + extra)) / (showStyle->divisions * edgeCount) - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- if (edgeCount == 2) {
- if (horizontal) {
- int temp = rect.left;
- rect.left = showStyle->width - rect.right - 1;
- rect.right = showStyle->width - temp - 1;
- } else {
- int temp = rect.top;
- rect.top = showStyle->height - rect.bottom - 1;
- rect.bottom = showStyle->height - temp - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
- }
- }
-}
-
-void GfxFrameout::prepareShowStyleIris(ShowStyleEntry *const showStyle, const int16 priority) {
- const int edgeCount = 4;
- const int numScreenItems = showStyle->divisions * edgeCount;
-
- showStyle->edgeCount = edgeCount;
- showStyle->screenItems.reserve(numScreenItems);
-
- CelInfo32 celInfo;
- celInfo.bitmap = NULL_REG;
- celInfo.type = kCelObjTypeView;
- celInfo.color = showStyle->color;
-
- for (int i = 0; i < numScreenItems; ++i) {
- Common::Rect rect;
-
- rect.right = showStyle->width - ((showStyle->width * i) / (showStyle->divisions * 2)) - 1;
- rect.left = (showStyle->width * i) / (showStyle->divisions * 2);
- rect.top = (showStyle->height * i) / (showStyle->divisions * 2);
- rect.bottom = ((i + 1) * (showStyle->height + 1)) / (showStyle->divisions * 2) - 1;
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- {
- int temp = rect.top;
- rect.top = showStyle->height - rect.bottom - 1;
- rect.bottom = showStyle->height - temp - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- rect.top = ((i + 1) * (showStyle->height + 1)) / (showStyle->divisions * 2);
- rect.right = ((i + 1) * (showStyle->width + 1)) / (showStyle->divisions * 2) - 1;
- rect.bottom = ((i + 1) * (showStyle->height + 1)) / (showStyle->divisions * 2) - 1;
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
-
- {
- int temp = rect.left;
- rect.left = showStyle->width - rect.right - 1;
- rect.right = showStyle->width - temp - 1;
- }
-
- addFrameoutEntryInternal(showStyle, priority, celInfo, rect);
- }
-}
-
-void GfxFrameout::prepareShowStylePixels(ShowStyleEntry *const showStyle, const int16 priority, const Common::Rect planeGameRect) {
- const int bitmapSize = showStyle->width * showStyle->height;
-
- // TODO: Verify that memory type 0x200 (what GK1 engine uses)
- // is Hunk type
- reg_t bitmapMemId = _segMan->allocateHunkEntry("ShowStylePixels()", bitmapSize + sizeof(GfxBitmapHeader));
- showStyle->bitmapMemId = bitmapMemId;
-
- // TODO: SCI2 GK1 uses a Bitmap constructor function to
- // do this work
- byte *bitmap = _segMan->getHunkPointer(bitmapMemId);
- GfxBitmapHeader *header = (GfxBitmapHeader *)bitmap;
- byte *bitmapData = bitmap + sizeof(GfxBitmapHeader);
-
- // TODO: These are defaults from the Bitmap constructor in
- // GK1, not specific values set by this function.
- // TODO: This probably should not even be using a struct at
- // all since this information is machine endian dependent
- // and will be reversed for Mac versions or when running
- // ScummVM on big-endian systems. GK1 used packed structs
- // everywhere so this probably worked better there too.
- header->field_18 = 36;
- header->field_1c = 36;
- memset(header, 0, sizeof(GfxBitmapHeader));
-
- header->width = showStyle->width;
- header->height = showStyle->height;
- header->field_8 = 250;
- header->size = bitmapSize;
-
- // TODO: Scaled dimensions in bitmap headers was not added
- // until SCI2.1mid. It is not clear what the right thing to
- // do here is.
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
- header->scaledWidth = _currentBuffer.scriptWidth;
- header->scaledHeight = _currentBuffer.scriptHeight;
- }
-
- Common::Rect copyRect;
- // TODO: planeGameRect is supposedly in script coordinates,
- // which are usually 320x200. If bitsSaveDisplayScreen is
- // in native resolution then seemingly this function will
- // not work properly since we will be not copy enough bits,
- // or from the correct location.
- copyRect.left = planeGameRect.left;
- copyRect.top = planeGameRect.top;
- copyRect.right = planeGameRect.left + showStyle->width;
- copyRect.bottom = planeGameRect.top + showStyle->height;
- _screen->bitsSaveDisplayScreen(copyRect, bitmapData);
-
- CelInfo32 celInfo;
- celInfo.bitmap = bitmapMemId;
- celInfo.type = kCelObjTypeMem;
-
- ScreenItem *screenItem = new ScreenItem;
-
- screenItem->position.x = 0;
- screenItem->position.y = 0;
-
- showStyle->bitmapScreenItem = screenItem;
- screenItem->priority = priority;
-
- // TODO: Have not seen/identified this particular flag yet in
- // SCI2.1mid (SQ6) engine; maybe (1) a duplicate of `created`,
- // or (2) does not exist any more, or (3) one of the other
- // still-unidentified fields. Probably need to look at the
- // GK1 source for its use in drawing algorithms to determine
- // if/how this correlates to ScreenItem members in the
- // SCI2.1mid engine.
-// screenItem->isInList = true;
-
- Plane *plane = _planes.findByObject(showStyle.plane);
- plane->_screenItemList.add(screenItem);
-}
-#endif
-
// NOTE: Different version of SCI engine support different show styles
// SCI2 implements 0, 1/3/5/7/9, 2/4/6/8/10, 11, 12, 13, 14
// SCI2.1 implements 0, 1/2/3/4/5/6/7/8/9/10/11/12/15, 13, 14
@@ -1528,53 +1483,15 @@ void GfxFrameout::processShowStyles() {
case kShowStyleWipeLeft:
case kShowStyleWipeUp:
case kShowStyleIrisOut:
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyleWipe(-1, showStyle);
- }
-#endif
- break;
case kShowStyleHShutterIn:
case kShowStyleVShutterIn:
case kShowStyleWipeRight:
case kShowStyleWipeDown:
case kShowStyleIrisIn:
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyleWipe(1, showStyle);
- }
-#endif
- break;
case kShowStyle11:
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyle11(showStyle);
- }
-#endif
- break;
case kShowStyle12:
case kShowStyleUnknown: {
-#if 0
- if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
-#endif
- retval = processShowStyleMorph(showStyle);
-#if 0
- } else {
- retval = processShowStyle12(showStyle);
- }
-#endif
+ retval = processShowStyleMorph(showStyle);
break;
}
case kShowStyleFadeOut: {
@@ -1599,17 +1516,18 @@ void GfxFrameout::processShowStyles() {
}
}
+ if (g_engine->shouldQuit()) {
+ return;
+ }
+
if (doFrameOut) {
- Common::Rect frameOutRect(0, 0);
- frameOut(true, frameOutRect);
-
- // TODO: It seems like transitions without the “animateâ€
- // flag are too fast in in SCI2–2.1early, but the throttle
- // value is arbitrary. Someone on real hardware probably
- // needs to test what the actual speed of transitions
- // should be
- //state->speedThrottler(30);
- //state->_throttleTrigger = true;
+ frameOut(true);
+
+ // TODO: Transitions without the “animate†flag are too
+ // fast, but the throttle value is arbitrary. Someone on
+ // real hardware probably needs to test what the actual
+ // speed of these transitions should be
+ throttle();
}
} while(continueProcessing && doFrameOut);
}
@@ -1669,369 +1587,123 @@ bool GfxFrameout::processShowStyleFade(const int direction, ShowStyleEntry *cons
return false;
}
-// TODO: Rect sizes are wrong, rects in SCI are inclusive of bottom/right but
-// in ScummVM are exclusive so extra ±1 operations here are wrong
-#if 0
-bool GfxFrameout::processShowStyleWipe(const ShowStyleEntry *const style) {
- const int16 divisions = style->divisions;
- Common::Rect rect(divisions, divisions);
-
- const Plane *const plane = _visibleScreen->planeList->findByObject(style->plane);
-
- const int16 planeLeft = plane->field_4C.left;
- const int16 planeTop = plane->field_4C.top;
- const int16 planeRight = plane->field_4C.right;
- const int16 planeBottom = plane->field_4C.bottom;
- const int16 planeWidth = planeRight - planeLeft + 1;
- const int16 planeHeight = planeBottom - planeTop + 1;
-
- const int16 divisionWidth = planeWidth / divisions - 1;
- int16 shutterDivisionWidth = planeWidth / (2 * divisions);
- if (shutterDivisionWidth >= 0) {
- const int16 heightPerDivision = planeHeight / divisions;
- int16 shutterMiddleX = divisions * shutterDivisionWidth;
- for (int16 x = divisionWidth - shutterDivisionWidth; x <= divisionWidth; ++x) {
- int16 divisionTop = 0;
- for (int16 y = 0; y < heightPerDivision; ++y, divisionTop += divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + divisions - 1;
- rect.left = planeLeft + shutterMiddleX;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- // number of divisions does not divide evenly into plane height,
- // draw the remainder
- if (planeHeight % divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + planeHeight % divisions - 1;
- rect.left = planeLeft + shutterMiddleX;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
-
- divisionTop = 0;
- for (int16 y = 0; y < heightPerDivision; ++y, divisionTop += divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + divisions - 1;
- rect.left = planeLeft + divisions * x;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- if (planeHeight % divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + planeHeight % divisions - 1;
- rect.left = planeLeft + divisions * x;
- rect.right = rect.left + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
-
- shutterMiddleX -= divisions;
- --shutterDivisionWidth;
- }
- }
+void GfxFrameout::kernelFrameOut(const bool shouldShowBits) {
+ if (_showStyles != nullptr) {
+ processShowStyles();
+ } else if (_palMorphIsOn) {
+ palMorphFrameOut(_styleRanges, nullptr);
+ _palMorphIsOn = false;
+ } else {
+// TODO: Window scroll
+// if (g_PlaneScroll) {
+// processScrolls();
+// }
- if (planeWidth % divisions) {
- const int16 roundedPlaneWidth = divisions * divisionWidth;
- int16 divisionTop = 0;
- for (int16 y = 0; y < planeHeight / divisions; ++y, divisionTop += divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + divisions - 1;
- rect.left = planeLeft + roundedPlaneWidth;
- rect.right = rect.left + planeWidth % divisions + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
- if (planeHeight % divisions) {
- rect.top = planeTop + divisionTop;
- rect.bottom = rect.top + planeHeight % divisions - 1;
- rect.left = planeLeft + roundedPlaneWidth;
- rect.right = rect.left + planeWidth % divisions + divisions - 1;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
- }
+ frameOut(shouldShowBits);
}
- rect.right = planeRight;
- rect.left = planeLeft;
- rect.top = planeTop;
- rect.bottom = planeBottom;
- // _screen->rectList.clear();
- // _screen->rectList.add(rect);
- // showBits();
+ throttle();
}
-#endif
-#if 0
-bool GfxFrameout::processShowStyleWipe(const int direction, ShowStyleEntry *const showStyle) {
- if (showStyle->currentStep < showStyle->divisions) {
- int index;
- if (direction <= 0) {
- index = showStyle->divisions - showStyle->currentStep - 1;
+
+void GfxFrameout::throttle() {
+ if (_throttleFrameOut) {
+ uint8 throttleTime;
+ if (_throttleState == 2) {
+ throttleTime = 17;
+ _throttleState = 0;
} else {
- index = showStyle->currentStep;
+ throttleTime = 16;
+ ++_throttleState;
}
- index *= showStyle->edgeCount;
-
- if (showStyle->edgeCount > 0) {
- for (int i = 0; i < showStyle->edgeCount; ++i) {
- if (showStyle->fadeUp) {
- ScreenItem *screenItem = showStyle->screenItems[index + i];
- if (screenItem != nullptr) {
- // TODO: _screen->deleteScreenItem(screenItem);
- _screenItems.remove(screenItem);
-
- delete screenItem;
- showStyle->screenItems[index + i] = nullptr;
- }
- } else {
- ScreenItem *screenItem = showStyle->screenItems[index + i];
- // TODO: _screen->addScreenItem(screenItem);
- _screenItems.push_back(screenItem);
- }
- }
-
- ++showStyle->currentStep;
- showStyle->nextTick += showStyle->delay;
- }
+ g_sci->getEngineState()->speedThrottler(throttleTime);
+ g_sci->getEngineState()->_throttleTrigger = true;
}
+}
- if (showStyle->currentStep >= showStyle->divisions) {
- if (showStyle->fadeUp) {
- showStyle->processed = true;
- }
+#pragma mark -
+#pragma mark Mouse cursor
- return true;
+reg_t GfxFrameout::kernelIsOnMe(const reg_t object, const Common::Point &position, bool checkPixel) const {
+ const reg_t planeObject = readSelector(_segMan, object, SELECTOR(plane));
+ Plane *plane = _visiblePlanes.findByObject(planeObject);
+ if (plane == nullptr) {
+ return make_reg(0, 0);
}
- return false;
-}
-
-void fillRect(byte *data, const Common::Rect &rect, const int16 color, const int16 stride) {
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(object);
+ if (screenItem == nullptr) {
+ return make_reg(0, 0);
+ }
+ // NOTE: The original engine passed a copy of the ScreenItem into isOnMe
+ // as a hack around the fact that the screen items in `_visiblePlanes`
+ // did not have their `_celObj` pointers cleared when their CelInfo was
+ // updated by `Plane::decrementScreenItemArrayCounts`. We handle this
+ // this more intelligently by clearing `_celObj` in the copy assignment
+ // operator, which is only ever called by `decrementScreenItemArrayCounts`
+ // anyway.
+ return make_reg(0, isOnMe(*screenItem, *plane, position, checkPixel));
}
-bool GfxFrameout::processShowStyle11(ShowStyleEntry *const showStyle) {
- int divisions = showStyle->divisions * showStyle->divisions;
+bool GfxFrameout::isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const {
- byte *bitmapData = _segMan->getHunkPointer(showStyle->bitmapMemId) + sizeof(GfxBitmapHeader);
-
- int ebx;
-
- if (showStyle->currentStep == 0) {
- int ctr = 0;
- int bloot = divisions;
- do {
- bloot >>= 1;
- ++ctr;
- } while (bloot != 1);
-
- showStyle->dissolveSeed = _dissolveSequenceSeeds[ctr];
- ebx = 800;
- showStyle->unknown3A = 800;
- showStyle->dissolveInitial = 800;
- } else {
- int ebx = showStyle->unknown3A;
- do {
- int eax = ebx >> 1;
- if (ebx & 1) {
- ebx = showStyle->dissolveSeed ^ eax;
- } else {
- ebx = eax;
- }
- } while (ebx >= divisions);
+ Common::Point scaledPosition(position);
+ mulru(scaledPosition, Ratio(_currentBuffer.screenWidth, _currentBuffer.scriptWidth), Ratio(_currentBuffer.screenHeight, _currentBuffer.scriptHeight));
+ scaledPosition.x += plane._planeRect.left;
+ scaledPosition.y += plane._planeRect.top;
- if (ebx == showStyle->dissolveInitial) {
- ebx = 0;
- }
+ if (!screenItem._screenRect.contains(scaledPosition)) {
+ return false;
}
- Common::Rect rect;
-
- rect.left = (showStyle->width + showStyle->divisions - 1) / showStyle->divisions;
- rect.top = (showStyle->height + showStyle->divisions - 1) / showStyle->divisions;
-
- if (showStyle->currentStep <= showStyle->divisions) {
- int ebp = 0;
- do {
- int ecx = ebx % showStyle->divisions;
+ if (checkPixel) {
+ CelObj &celObj = screenItem.getCelObj();
- Common::Rect drawRect;
- drawRect.left = rect.left * ecx;
- drawRect.right = drawRect.left + rect.left - 1;
- drawRect.top = rect.top * ebx;
- drawRect.bottom = rect.top * ebx + rect.top - 1;
+ bool mirrorX = screenItem._mirrorX ^ celObj._mirrorX;
- bool doit;
- if (drawRect.right >= 0 && drawRect.bottom >= 0 && drawRect.left <= rect.right && drawRect.top <= rect.bottom) {
- doit = true;
- } else {
- doit = false;
- }
+ scaledPosition.x -= screenItem._scaledPosition.x;
+ scaledPosition.y -= screenItem._scaledPosition.y;
- if (doit) {
- if (drawRect.left < 0) {
- drawRect.left = 0;
- }
+ mulru(scaledPosition, Ratio(celObj._scaledWidth, _currentBuffer.screenWidth), Ratio(celObj._scaledHeight, _currentBuffer.screenHeight));
- if (drawRect.top < 0) {
- drawRect.top = 0;
- }
-
- if (drawRect.right > rect.right) {
- drawRect.right = rect.right;
- }
-
- if (drawRect.bottom > rect.bottom) {
- drawRect.bottom = rect.bottom;
- }
- } else {
- drawRect.right = 0;
- drawRect.bottom = 0;
- drawRect.left = 0;
- drawRect.top = 0;
- }
-
- fillRect(bitmapData, drawRect, showStyle->color, showStyle->width);
-
- int eax = ebx;
- do {
- eax >>= 1;
- if (ebx & 1) {
- ebx = showStyle->dissolveSeed;
- ebx ^= eax;
- } else {
- ebx = eax;
- }
- } while (ebx >= divisions);
-
- if (showStyle->currentStep != showStyle->divisions) {
- ebp++;
- } else {
- drawRect.left = 0;
- drawRect.top = 0;
- drawRect.right = showStyle->width - 1;
- drawRect.bottom = showStyle->height - 1;
- fillRect(bitmapData, drawRect, showStyle->color, showStyle->width);
- }
-
- } while (ebp <= showStyle->divisions);
-
- showStyle->unknown3A = ebx;
- ++showStyle->currentStep;
- showStyle->nextTick += showStyle->delay;
- // _screen->updateScreenItem(showStyle->bitmapScreenItem);
- }
-
- if (showStyle->currentStep >= showStyle->divisions) {
- if (showStyle->fadeUp) {
- showStyle->processed = true;
+ if (screenItem._scale.signal != kScaleSignalNone && screenItem._scale.x && screenItem._scale.y) {
+ scaledPosition.x = scaledPosition.x * 128 / screenItem._scale.x;
+ scaledPosition.y = scaledPosition.y * 128 / screenItem._scale.y;
}
- return true;
+ uint8 pixel = celObj.readPixel(scaledPosition.x, scaledPosition.y, mirrorX);
+ return pixel != celObj._transparentColor;
}
- return false;
-}
-
-bool GfxFrameout::processShowStyle12(ShowStyleEntry *const showStyle) {
return true;
}
-#endif
-void GfxFrameout::kernelFrameout(const bool shouldShowBits) {
- if (_showStyles != nullptr) {
- processShowStyles();
- } else if (_palMorphIsOn) {
- palMorphFrameOut(_styleRanges, nullptr);
- _palMorphIsOn = false;
- } else {
-// TODO: Window scroll
-// if (g_ScrollWindow) {
-// doScroll();
-// }
+void GfxFrameout::kernelSetNowSeen(const reg_t screenItemObject) const {
+ const reg_t planeObject = readSelector(_segMan, screenItemObject, SELECTOR(plane));
- Common::Rect frameOutRect(0, 0);
- frameOut(shouldShowBits, frameOutRect);
- }
-}
-
-uint16 GfxFrameout::kernelIsOnMe(int16 x, int16 y, uint16 checkPixels, reg_t screenObject) {
- reg_t planeObject = readSelector(_segMan, screenObject, SELECTOR(plane));
- Plane *screenItemPlane = _visiblePlanes.findByObject(planeObject); // Search for plane in visible planes
- ScreenItem *screenItem = nullptr;
-
- if (!screenItemPlane) {
- // Specified plane not found
- return 0;
+ Plane *plane = _planes.findByObject(planeObject);
+ if (plane == nullptr) {
+ error("kSetNowSeen: Plane %04x:%04x not found for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(screenItemObject));
}
- screenItem = screenItemPlane->_screenItemList.findByObject(screenObject);
- if (!screenItem) {
- // Specified screen object not in item list
- return 0;
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject);
+ if (screenItem == nullptr) {
+ error("kSetNowSeen: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItemObject), PRINT_REG(planeObject));
}
- // Original SCI32 seems to have made a copy (?) of the screenitem?
- // there is also a "or [ebp+arg_56], 1 - not sure what that did
- return isOnMe(screenItemPlane, screenItem, x, y, checkPixels);
+ Common::Rect result = screenItem->getNowSeenRect(*plane);
+ writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsLeft), result.left);
+ writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsTop), result.top);
+ writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsRight), result.right - 1);
+ writeSelectorValue(_segMan, screenItemObject, SELECTOR(nsBottom), result.bottom - 1);
}
-uint16 GfxFrameout::isOnMe(Plane *screenItemPlane, ScreenItem *screenItem, int16 x, int16 y, uint16 checkPixels) {
- // adjust coordinate according to resolution
- int32 adjustedX = x * getCurrentBuffer().screenWidth / getCurrentBuffer().scriptWidth;
- int32 adjustedY = y * getCurrentBuffer().screenHeight / getCurrentBuffer().scriptHeight;
-
- adjustedX += screenItemPlane->_planeRect.left;
- adjustedY += screenItemPlane->_planeRect.top;
-
- //warning("kIsOnMe %s %d (%d, %d -> %d, %d) mouse %d, %d", _segMan->getObjectName(screenObject), checkPixels, screenItem->_screenRect.left, screenItem->_screenRect.top, screenItem->_screenRect.right, screenItem->_screenRect.bottom, adjustedX, adjustedY);
-
- if (!screenItem->_screenRect.contains(adjustedX, adjustedY)) {
- // Specified coordinates are not within screen item
- return 0;
- }
-
- //warning("HIT!");
- if (checkPixels) {
- //warning("Check Pixels");
- CelObj &screenItemCelObject = screenItem->getCelObj();
-
- Common::Point celAdjustedPoint(adjustedX, adjustedY);
- bool celMirrored = screenItem->_mirrorX ^ screenItemCelObject._mirrorX;
-
- celAdjustedPoint.x -= screenItem->_scaledPosition.x;
- celAdjustedPoint.y -= screenItem->_scaledPosition.y;
-
- Ratio celAdjustXRatio(screenItemCelObject._scaledWidth, getCurrentBuffer().screenWidth);
- Ratio celAdjustYRatio(screenItemCelObject._scaledHeight, getCurrentBuffer().screenHeight);
- mulru(celAdjustedPoint, celAdjustXRatio, celAdjustYRatio);
-
- if ((screenItem->_scale.signal) && (screenItem->_scale.x) && (screenItem->_scale.y)) {
- // Apply scaling
- celAdjustedPoint.x = celAdjustedPoint.x * 128 / screenItem->_scale.x;
- celAdjustedPoint.y = celAdjustedPoint.y * 128 / screenItem->_scale.y;
- }
-
- byte coordinateColor = screenItemCelObject.readPixel(celAdjustedPoint.x, celAdjustedPoint.y, celMirrored);
- byte transparentColor = screenItemCelObject._transparentColor;
-
- if (coordinateColor == transparentColor) {
- // Coordinate is transparent
- //warning("TRANSPARENT!");
- return 0;
- }
+void GfxFrameout::remapMarkRedraw() {
+ for (PlaneList::const_iterator it = _planes.begin(); it != _planes.end(); ++it) {
+ Plane *p = *it;
+ p->remapMarkRedraw();
}
- return 1;
}
#pragma mark -
@@ -2052,6 +1724,15 @@ void GfxFrameout::printVisiblePlaneList(Console *con) const {
printPlaneListInternal(con, _visiblePlanes);
}
+void GfxFrameout::printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const {
+ ScreenItemList::size_type i = 0;
+ for (ScreenItemList::const_iterator sit = screenItemList.begin(); sit != screenItemList.end(); sit++) {
+ ScreenItem *screenItem = *sit;
+ con->debugPrintf("%2d: ", i++);
+ screenItem->printDebugInfo(con);
+ }
+}
+
void GfxFrameout::printPlaneItemList(Console *con, const reg_t planeObject) const {
Plane *p = _planes.findByObject(planeObject);
@@ -2060,12 +1741,18 @@ void GfxFrameout::printPlaneItemList(Console *con, const reg_t planeObject) cons
return;
}
- ScreenItemList::size_type i = 0;
- for (ScreenItemList::iterator sit = p->_screenItemList.begin(); sit != p->_screenItemList.end(); sit++) {
- ScreenItem *screenItem = *sit;
- con->debugPrintf("%2d: ", i++);
- screenItem->printDebugInfo(con);
+ printPlaneItemListInternal(con, p->_screenItemList);
+}
+
+void GfxFrameout::printVisiblePlaneItemList(Console *con, const reg_t planeObject) const {
+ Plane *p = _visiblePlanes.findByObject(planeObject);
+
+ if (p == nullptr) {
+ con->debugPrintf("Plane does not exist");
+ return;
}
+
+ printPlaneItemListInternal(con, p->_screenItemList);
}
} // End of namespace Sci
diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h
index 0da6866f7c..99658ede6a 100644
--- a/engines/sci/graphics/frameout.h
+++ b/engines/sci/graphics/frameout.h
@@ -130,64 +130,6 @@ struct ShowStyleEntry {
bool processed;
//
- // Engine-specific properties for SCI2 through 2.1early
- //
-
- // TODO: Could union this stuff to save literally
- // several bytes of memory.
-
- /**
- * The width of the plane. Used to determine the correct
- * size of screen items for wipes.
- */
- int width;
-
- /**
- * The height of the plane. Used to determine the correct
- * size of screen items for wipes.
- */
- int height;
-
- /**
- * The number of edges that a transition operates on.
- * Slide wipe: 1 edge
- * Reveal wipe: 2 edges
- * Iris wipe: 4 edges
- */
- // TODO: I have no idea why SCI engine stores this instead
- // of a screenItems count
- int edgeCount;
-
- /**
- * Used by transition types 1 through 10.
- * One screen item per division per edge.
- */
- ScreenItemList screenItems;
-
- /**
- * Used by transition types 11 and 12. A copy of the
- * visible frame buffer.
- */
- // TODO: This is a reg_t in SCI engine; not sure if
- // we can avoid allocation through SegMan or not.
- reg_t bitmapMemId;
-
- /**
- * Used by transition types 11 and 12. A screen item
- * used to display the associated bitmap data.
- */
- ScreenItem *bitmapScreenItem;
-
- /**
- * A number used to pick pixels to dissolve by types
- * 11 and 12.
- */
- int dissolveSeed;
- int unknown3A;
- // max?
- int dissolveInitial;
-
- //
// Engine specific properties for SCI2.1mid through SCI3
//
@@ -207,10 +149,7 @@ struct ShowStyleEntry {
typedef Common::Array<DrawList> ScreenItemListList;
typedef Common::Array<RectList> EraseListList;
-class GfxCache;
class GfxCoordAdjuster32;
-class GfxPaint32;
-class GfxPalette;
class GfxScreen;
/**
@@ -220,16 +159,14 @@ class GfxScreen;
class GfxFrameout {
private:
bool _isHiRes;
- GfxCache *_cache;
GfxCoordAdjuster32 *_coordAdjuster;
GfxPalette32 *_palette;
ResourceManager *_resMan;
GfxScreen *_screen;
SegManager *_segMan;
- GfxPaint32 *_paint32;
public:
- GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxCache *cache, GfxScreen *screen, GfxPalette32 *palette, GfxPaint32 *paint32);
+ GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette);
~GfxFrameout();
void clear();
@@ -237,14 +174,62 @@ public:
void run();
#pragma mark -
+#pragma mark Benchmarking
+private:
+ /**
+ * Optimization to avoid the more expensive object name
+ * comparision on every call to kAddScreenItem and
+ * kRemoveScreenItem.
+ */
+ bool _benchmarkingFinished;
+
+ /**
+ * Whether or not calls to kFrameOut should be framerate
+ * limited to 60fps.
+ */
+ bool _throttleFrameOut;
+
+ /**
+ * Determines whether or not a screen item is the "Fred"
+ * object.
+ */
+ bool checkForFred(const reg_t object);
+
+#pragma mark -
#pragma mark Screen items
private:
- void deleteScreenItem(ScreenItem *screenItem, const reg_t plane);
+ void remapMarkRedraw();
public:
+ /**
+ * Adds a screen item.
+ */
+ void addScreenItem(ScreenItem &screenItem) const;
+
+ /**
+ * Updates a screen item.
+ */
+ void updateScreenItem(ScreenItem &screenItem) const;
+
+ /**
+ * Deletes a screen item.
+ */
+ void deleteScreenItem(ScreenItem &screenItem);
+
+ /**
+ * Deletes a screen item from the given plane.
+ */
+ void deleteScreenItem(ScreenItem &screenItem, Plane &plane);
+
+ /**
+ * Deletes a screen item from the given plane.
+ */
+ void deleteScreenItem(ScreenItem &screenItem, const reg_t plane);
+
void kernelAddScreenItem(const reg_t object);
void kernelUpdateScreenItem(const reg_t object);
void kernelDeleteScreenItem(const reg_t object);
+ void kernelSetNowSeen(const reg_t screenItemObject) const;
#pragma mark -
#pragma mark Planes
@@ -259,6 +244,13 @@ private:
PlaneList _planes;
/**
+ * Updates an existing plane with properties from the
+ * given VM object.
+ */
+ void updatePlane(Plane &plane);
+
+public:
+ /**
* Creates and adds a new plane to the plane list, or
* cancels deletion and updates an already-existing
* plane if a plane matching the given plane VM object
@@ -270,18 +262,23 @@ private:
void addPlane(Plane &plane);
/**
- * Updates an existing plane with properties from the
- * given VM object.
+ * Deletes a plane within the current plane list.
+ *
+ * @note This method is on Screen in SCI engine, but it
+ * is only ever called on `GraphicsMgr.screen`.
*/
- void updatePlane(Plane &plane);
+ void deletePlane(Plane &plane);
-public:
const PlaneList &getPlanes() const {
return _planes;
}
+ const PlaneList &getVisiblePlanes() const {
+ return _visiblePlanes;
+ }
void kernelAddPlane(const reg_t object);
void kernelUpdatePlane(const reg_t object);
void kernelDeletePlane(const reg_t object);
+ void kernelMovePlaneItems(const reg_t object, const int16 deltaX, const int16 deltaY, const bool scrollPics);
int16 kernelGetHighPlanePri();
#pragma mark -
@@ -312,19 +309,22 @@ private:
bool processShowStyleNone(ShowStyleEntry *showStyle);
bool processShowStyleMorph(ShowStyleEntry *showStyle);
bool processShowStyleFade(const int direction, ShowStyleEntry *showStyle);
-#if 0
- bool processShowStyleWipe(const int direction, ShowStyleEntry *const showStyle);
-#endif
public:
// NOTE: This signature is taken from SCI3 Phantasmagoria 2
// and is valid for all implementations of SCI32
- void kernelSetShowStyle(const uint16 argc, const reg_t &planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, const reg_t &pFadeArray, const int16 divisions, const int16 blackScreen);
+ void kernelSetShowStyle(const uint16 argc, const reg_t planeObj, const ShowStyleType type, const int16 seconds, const int16 direction, const int16 priority, const int16 animate, const int16 frameOutNow, reg_t pFadeArray, int16 divisions, const int16 blackScreen);
#pragma mark -
#pragma mark Rendering
private:
/**
+ * State tracker to provide more accurate 60fps
+ * video throttling.
+ */
+ uint8 _throttleState;
+
+ /**
* TODO: Documentation
*/
int8 _styleRanges[256];
@@ -338,15 +338,10 @@ private:
*/
Buffer _currentBuffer;
- // TODO: In SCI2.1/SQ6, priority map pixels are not allocated
- // by default. In SCI2/GK1, pixels are allocated, but not used
- // anywhere except within CelObj::Draw in seemingly the same
- // way they are used in SCI2.1/SQ6: that is, never read, only
- // written.
- Buffer _priorityMap;
-
/**
- * TODO: Documentation
+ * When true, a change to the remap zone in the palette
+ * has occurred and screen items with remap data need to
+ * be redrawn.
*/
bool _remapOccurred;
@@ -404,8 +399,10 @@ private:
* over the entire screen for rendering the next frame.
* The draw and erase lists in `drawLists` and
* `eraseLists` each represent one plane on the screen.
+ * The optional `eraseRect` argument allows a specific
+ * area of the screen to be erased.
*/
- void calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &calcRect);
+ void calcLists(ScreenItemListList &drawLists, EraseListList &eraseLists, const Common::Rect &eraseRect = Common::Rect());
/**
* Erases the areas in the given erase list from the
@@ -423,13 +420,6 @@ private:
void drawScreenItemList(const DrawList &screenItemList);
/**
- * Updates the internal screen buffer for the next
- * frame. If `shouldShowBits` is true, also sends the
- * buffer to hardware.
- */
- void frameOut(const bool shouldShowBits, const Common::Rect &rect);
-
- /**
* Adds a new rectangle to the list of regions to write
* out to the hardware. The provided rect may be merged
* into an existing rectangle to reduce the number of
@@ -450,23 +440,31 @@ private:
public:
/**
- * TODO: Document
- * This is used by CelObj::Draw.
- */
- bool _hasRemappedScreenItem;
-
- /**
* Whether palMorphFrameOut should be used instead of
* frameOut for rendering. Used by kMorphOn to
* explicitly enable palMorphFrameOut for one frame.
*/
bool _palMorphIsOn;
- inline Buffer &getCurrentBuffer() {
+ inline const Buffer &getCurrentBuffer() const {
return _currentBuffer;
}
- void kernelFrameout(const bool showBits);
+ void kernelFrameOut(const bool showBits);
+
+ /**
+ * Throttles the engine as necessary to maintain
+ * 60fps output.
+ */
+ void throttle();
+
+ /**
+ * Updates the internal screen buffer for the next
+ * frame. If `shouldShowBits` is true, also sends the
+ * buffer to hardware. If `eraseRect` is non-empty,
+ * it is added to the erase list for this frame.
+ */
+ void frameOut(const bool shouldShowBits, const Common::Rect &eraseRect = Common::Rect());
/**
* Modifies the raw pixel data for the next frame with
@@ -474,11 +472,6 @@ public:
*/
void alterVmap(const Palette &palette1, const Palette &palette2, const int8 style, const int8 *const styleRanges);
- // TODO: SCI2 engine never uses priority map?
- inline Buffer &getPriorityMap() {
- return _priorityMap;
- }
-
// NOTE: This function is used within ScreenItem subsystem and assigned
// to various booleanish fields that seem to represent the state of the
// screen item (created, updated, deleted). In GK1/DOS, Phant1/m68k,
@@ -491,8 +484,17 @@ public:
return 1;
};
- uint16 kernelIsOnMe(int16 x, int16 y, uint16 checkPixels, reg_t screenObject);
- uint16 isOnMe(Plane *screenItemPlane, ScreenItem *screenItem, int16 x, int16 y, uint16 checkPixels);
+#pragma mark -
+#pragma mark Mouse cursor
+private:
+ /**
+ * Determines whether or not the point given by
+ * `position` is inside of the given screen item.
+ */
+ bool isOnMe(const ScreenItem &screenItem, const Plane &plane, const Common::Point &position, const bool checkPixel) const;
+
+public:
+ reg_t kernelIsOnMe(const reg_t object, const Common::Point &position, const bool checkPixel) const;
#pragma mark -
#pragma mark Debugging
@@ -501,6 +503,8 @@ public:
void printVisiblePlaneList(Console *con) const;
void printPlaneListInternal(Console *con, const PlaneList &planeList) const;
void printPlaneItemList(Console *con, const reg_t planeObject) const;
+ void printVisiblePlaneItemList(Console *con, const reg_t planeObject) const;
+ void printPlaneItemListInternal(Console *con, const ScreenItemList &screenItemList) const;
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h
index fbad120374..3fcc83c5e2 100644
--- a/engines/sci/graphics/helpers.h
+++ b/engines/sci/graphics/helpers.h
@@ -139,16 +139,28 @@ inline void mul(Common::Rect &rect, const Common::Rational &ratioX, const Common
}
/**
+ * Multiplies a rectangle by two ratios with default
+ * rounding. Modifies the rect directly. Uses inclusive
+ * rectangle rounding.
+ */
+inline void mulinc(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY) {
+ rect.left = (rect.left * ratioX).toInt();
+ rect.top = (rect.top * ratioY).toInt();
+ rect.right = ((rect.right - 1) * ratioX).toInt() + 1;
+ rect.bottom = ((rect.bottom - 1) * ratioY).toInt() + 1;
+}
+
+/**
* Multiplies a number by a rational number, rounding up to
* the nearest whole number.
*/
-inline int mulru(const int value, const Common::Rational &ratio) {
- int num = value * ratio.getNumerator();
+inline int mulru(const int value, const Common::Rational &ratio, const int extra = 0) {
+ int num = (value + extra) * ratio.getNumerator();
int result = num / ratio.getDenominator();
if (num > ratio.getDenominator() && num % ratio.getDenominator()) {
++result;
}
- return result;
+ return result - extra;
}
/**
@@ -165,19 +177,12 @@ inline void mulru(Common::Point &point, const Common::Rational &ratioX, const Co
* Multiplies a point by two rational numbers for X and Y,
* rounding up to the nearest whole number. Modifies the
* rect directly.
- *
- * @note In SCI engine, the bottom-right corner of rects
- * received an additional one pixel during the
- * multiplication in order to round up to include the
- * bottom-right corner. Since ScummVM rects do not include
- * the bottom-right corner, doing this ends up making rects
- * a pixel too wide/tall depending upon the remainder.
*/
-inline void mulru(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY) {
+inline void mulru(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY, const int extra) {
rect.left = mulru(rect.left, ratioX);
rect.top = mulru(rect.top, ratioY);
- rect.right = mulru(rect.right, ratioX);
- rect.bottom = mulru(rect.bottom, ratioY);
+ rect.right = mulru(rect.right - 1, ratioX, extra) + 1;
+ rect.bottom = mulru(rect.bottom - 1, ratioY, extra) + 1;
}
struct Buffer : public Graphics::Surface {
@@ -186,6 +191,12 @@ struct Buffer : public Graphics::Surface {
uint16 scriptWidth;
uint16 scriptHeight;
+ Buffer() :
+ screenWidth(0),
+ screenHeight(0),
+ scriptWidth(320),
+ scriptHeight(200) {}
+
Buffer(const uint16 width, const uint16 height, uint8 *const pix) :
screenWidth(width),
screenHeight(height),
@@ -226,7 +237,7 @@ struct Color {
return used == other.used && r == other.r && g == other.g && b == other.b;
}
inline bool operator!=(const Color &other) const {
- return !(*this == other);
+ return !operator==(other);
}
#endif
};
diff --git a/engines/sci/graphics/lists32.h b/engines/sci/graphics/lists32.h
index bb990e17ca..4f74c77325 100644
--- a/engines/sci/graphics/lists32.h
+++ b/engines/sci/graphics/lists32.h
@@ -36,7 +36,7 @@ namespace Sci {
* calling `erase` or when destroying the
* StablePointerArray.
*/
-template <class T, uint N>
+template<class T, uint N>
class StablePointerArray {
uint _size;
T *_items[N];
@@ -178,7 +178,7 @@ public:
}
};
-template <typename T>
+template<typename T>
class FindByObject {
const reg_t &_object;
public:
@@ -188,5 +188,5 @@ public:
}
};
-}
+} // End of namespace Sci
#endif
diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h
index 955cfdec8f..317388b2df 100644
--- a/engines/sci/graphics/paint16.h
+++ b/engines/sci/graphics/paint16.h
@@ -23,8 +23,6 @@
#ifndef SCI_GRAPHICS_PAINT16_H
#define SCI_GRAPHICS_PAINT16_H
-#include "sci/graphics/paint.h"
-
namespace Sci {
class GfxPorts;
@@ -36,7 +34,7 @@ class GfxView;
/**
* Paint16 class, handles painting/drawing for SCI16 (SCI0-SCI1.1) games
*/
-class GfxPaint16 : public GfxPaint {
+class GfxPaint16 {
public:
GfxPaint16(ResourceManager *resMan, SegManager *segMan, GfxCache *cache, GfxPorts *ports, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette *palette, GfxTransitions *transitions, AudioPlayer *audio);
~GfxPaint16();
diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp
index a210a469f1..74eb1629d0 100644
--- a/engines/sci/graphics/paint32.cpp
+++ b/engines/sci/graphics/paint32.cpp
@@ -20,49 +20,162 @@
*
*/
-#include "sci/sci.h"
-#include "sci/engine/state.h"
-#include "sci/engine/selector.h"
-#include "sci/graphics/coordadjuster.h"
-#include "sci/graphics/cache.h"
+#include "graphics/primitives.h"
+#include "sci/engine/seg_manager.h"
#include "sci/graphics/paint32.h"
-#include "sci/graphics/font.h"
-#include "sci/graphics/picture.h"
-#include "sci/graphics/view.h"
-#include "sci/graphics/screen.h"
-#include "sci/graphics/palette.h"
+#include "sci/graphics/text32.h"
namespace Sci {
-GfxPaint32::GfxPaint32(ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette *palette)
- : _resMan(resMan), _coordAdjuster(coordAdjuster), _screen(screen), _palette(palette) {
+GfxPaint32::GfxPaint32(SegManager *segMan) :
+ _segMan(segMan) {}
+
+reg_t GfxPaint32::kernelAddLine(const reg_t planeObject, const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness) {
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObject);
+ if (plane == nullptr) {
+ error("kAddLine: Plane %04x:%04x not found", PRINT_REG(planeObject));
+ }
+
+ Common::Rect gameRect;
+ BitmapResource bitmap = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
+
+ CelInfo32 celInfo;
+ celInfo.type = kCelTypeMem;
+ celInfo.bitmap = bitmap.getObject();
+ // SSCI stores the line color on `celInfo`, even though
+ // this is not a `kCelTypeColor`, as a hack so that
+ // `kUpdateLine` can get the originally used color
+ celInfo.color = color;
+
+ ScreenItem *screenItem = new ScreenItem(planeObject, celInfo, Common::Rect(startPoint.x, startPoint.y, startPoint.x + bitmap.getWidth(), startPoint.y + bitmap.getHeight()));
+ screenItem->_priority = priority;
+ screenItem->_fixedPriority = true;
+
+ plane->_screenItemList.add(screenItem);
+
+ return screenItem->_object;
+}
+
+void GfxPaint32::kernelUpdateLine(ScreenItem *screenItem, Plane *plane, const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness) {
+
+ Common::Rect gameRect;
+ BitmapResource bitmap = makeLineBitmap(startPoint, endPoint, priority, color, style, pattern, thickness, gameRect);
+
+ _segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
+ screenItem->_celInfo.bitmap = bitmap.getObject();
+ screenItem->_celInfo.color = color;
+ screenItem->_position = startPoint;
+ screenItem->_priority = priority;
+ screenItem->update();
}
-GfxPaint32::~GfxPaint32() {
+void GfxPaint32::kernelDeleteLine(const reg_t screenItemObject, const reg_t planeObject) {
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObject);
+ if (plane == nullptr) {
+ return;
+ }
+
+ ScreenItem *screenItem = plane->_screenItemList.findByObject(screenItemObject);
+ if (screenItem == nullptr) {
+ return;
+ }
+
+ _segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
+ g_sci->_gfxFrameout->deleteScreenItem(*screenItem, *plane);
}
-void GfxPaint32::fillRect(Common::Rect rect, byte color) {
- int16 y, x;
- Common::Rect clipRect = rect;
+void GfxPaint32::plotter(int x, int y, int color, void *data) {
+ LineProperties &properties = *static_cast<LineProperties *>(data);
+ byte *pixels = properties.bitmap->getPixels();
+
+ const uint32 index = properties.bitmap->getWidth() * y + x;
+
+ if (index < properties.bitmap->getDataSize()) {
+ if (properties.solid) {
+ pixels[index] = (uint8)color;
+ return;
+ }
+
+ if (properties.horizontal && x != properties.lastAddress) {
+ properties.lastAddress = x;
+ ++properties.patternIndex;
+ } else if (!properties.horizontal && y != properties.lastAddress) {
+ properties.lastAddress = y;
+ ++properties.patternIndex;
+ }
- clipRect.clip(_screen->getWidth(), _screen->getHeight());
+ if (properties.pattern[properties.patternIndex]) {
+ pixels[index] = (uint8)color;
+ }
- for (y = clipRect.top; y < clipRect.bottom; y++) {
- for (x = clipRect.left; x < clipRect.right; x++) {
- _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0);
+ if (properties.patternIndex == ARRAYSIZE(properties.pattern)) {
+ properties.patternIndex = 0;
}
+ } else {
+ warning("GfxPaint32::plotter: Attempted to write out of bounds (%u >= %u)", index, properties.bitmap->getDataSize());
}
}
-void GfxPaint32::kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
- GfxPicture *picture = new GfxPicture(_resMan, _coordAdjuster, 0, _screen, _palette, pictureId, false);
+BitmapResource GfxPaint32::makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, uint16 pattern, uint8 thickness, Common::Rect &outRect) {
+ const uint8 skipColor = color != 250 ? 250 : 0;
- picture->draw(animationNr, mirroredFlag, addToFlag, EGApaletteNo);
- delete picture;
-}
+ // Thickness is expected to be 2n+1
+ thickness = ((MAX((uint8)1, thickness) - 1) | 1);
+ const uint8 halfThickness = thickness >> 1;
+
+ outRect.left = (startPoint.x < endPoint.x ? startPoint.x : endPoint.x) - halfThickness;
+ outRect.top = (startPoint.y < endPoint.y ? startPoint.y : endPoint.y) - halfThickness;
+ outRect.right = (startPoint.x > endPoint.x ? startPoint.x : endPoint.x) + halfThickness + 1;
+ outRect.bottom = (startPoint.y > endPoint.y ? startPoint.y : endPoint.y) + halfThickness + 1;
+
+ BitmapResource bitmap(_segMan, outRect.width(), outRect.height(), skipColor, 0, 0, g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight, 0, false);
+
+ byte *pixels = bitmap.getPixels();
+ memset(pixels, skipColor, bitmap.getWidth() * bitmap.getHeight());
+
+ LineProperties properties;
+ properties.bitmap = &bitmap;
+
+ switch (style) {
+ case kLineStyleSolid:
+ pattern = 0xFFFF;
+ properties.solid = true;
+ break;
+ case kLineStyleDashed:
+ pattern = 0xFF00;
+ properties.solid = false;
+ break;
+ case kLineStylePattern:
+ properties.solid = pattern == 0xFFFF;
+ break;
+ }
+
+ const Common::Rect drawRect(
+ startPoint.x - outRect.left,
+ startPoint.y - outRect.top,
+ endPoint.x - outRect.left,
+ endPoint.y - outRect.top
+ );
-void GfxPaint32::kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) {
- _screen->drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, color, priority, control);
+ if (!properties.solid) {
+ for (int i = 0; i < ARRAYSIZE(properties.pattern); ++i) {
+ properties.pattern[i] = (pattern & 0x8000);
+ pattern <<= 1;
+ }
+
+ properties.patternIndex = 0;
+ properties.horizontal = ABS(drawRect.right - drawRect.left) > ABS(drawRect.bottom - drawRect.top);
+ properties.lastAddress = properties.horizontal ? drawRect.left : drawRect.top;
+ }
+
+ if (thickness <= 1) {
+ Graphics::drawLine(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom, color, plotter, &properties);
+ } else {
+ Graphics::drawThickLine2(drawRect.left, drawRect.top, drawRect.right, drawRect.bottom, thickness, color, plotter, &properties);
+ }
+
+ return bitmap;
}
+
} // End of namespace Sci
diff --git a/engines/sci/graphics/paint32.h b/engines/sci/graphics/paint32.h
index e7a3ec256d..6d5a957fcd 100644
--- a/engines/sci/graphics/paint32.h
+++ b/engines/sci/graphics/paint32.h
@@ -23,30 +23,48 @@
#ifndef SCI_GRAPHICS_PAINT32_H
#define SCI_GRAPHICS_PAINT32_H
-#include "sci/graphics/paint.h"
-
namespace Sci {
+class BitmapResource;
+class Plane;
+class ScreenItem;
+class SegManager;
-class GfxPorts;
+enum LineStyle {
+ kLineStyleSolid,
+ kLineStyleDashed,
+ kLineStylePattern
+};
/**
* Paint32 class, handles painting/drawing for SCI32 (SCI2+) games
*/
-class GfxPaint32 : public GfxPaint {
+class GfxPaint32 {
public:
- GfxPaint32(ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette *palette);
- ~GfxPaint32();
+ GfxPaint32(SegManager *segMan);
- void fillRect(Common::Rect rect, byte color);
+private:
+ SegManager *_segMan;
- void kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo);
- void kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control);
+#pragma mark -
+#pragma mark Line drawing
+public:
+ reg_t kernelAddLine(const reg_t planeObject, const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness);
+ void kernelUpdateLine(ScreenItem *screenItem, Plane *plane, const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness);
+ void kernelDeleteLine(const reg_t screenItemObject, const reg_t planeObject);
private:
- ResourceManager *_resMan;
- GfxCoordAdjuster *_coordAdjuster;
- GfxScreen *_screen;
- GfxPalette *_palette;
+ typedef struct {
+ BitmapResource *bitmap;
+ bool pattern[16];
+ uint8 patternIndex;
+ bool solid;
+ bool horizontal;
+ int lastAddress;
+ } LineProperties;
+
+ static void plotter(int x, int y, int color, void *data);
+
+ BitmapResource makeLineBitmap(const Common::Point &startPoint, const Common::Point &endPoint, const int16 priority, const uint8 color, const LineStyle style, const uint16 pattern, const uint8 thickness, Common::Rect &outRect);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp
index 6f6e0b672e..1514ad838f 100644
--- a/engines/sci/graphics/palette.cpp
+++ b/engines/sci/graphics/palette.cpp
@@ -32,6 +32,7 @@
#include "sci/graphics/cache.h"
#include "sci/graphics/maciconbar.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/view.h"
@@ -103,9 +104,6 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen)
default:
error("GfxPalette: Unknown view type");
}
-
- _remapOn = false;
- resetRemapping();
}
GfxPalette::~GfxPalette() {
@@ -336,79 +334,6 @@ void GfxPalette::set(Palette *newPalette, bool force, bool forceRealMerge) {
}
}
-byte GfxPalette::remapColor(byte remappedColor, byte screenColor) {
- assert(_remapOn);
- if (_remappingType[remappedColor] == kRemappingByRange)
- return _remappingByRange[screenColor];
- else if (_remappingType[remappedColor] == kRemappingByPercent)
- return _remappingByPercent[screenColor];
- else
- error("remapColor(): Color %d isn't remapped", remappedColor);
-
- return 0; // should never reach here
-}
-
-void GfxPalette::resetRemapping() {
- _remapOn = false;
- _remappingPercentToSet = 0;
-
- for (int i = 0; i < 256; i++) {
- _remappingType[i] = kRemappingNone;
- _remappingByPercent[i] = i;
- _remappingByRange[i] = i;
- }
-}
-
-void GfxPalette::setRemappingPercent(byte color, byte percent) {
- _remapOn = true;
-
- // We need to defer the setup of the remapping table every time the screen
- // palette is changed, so that kernelFindColor() can find the correct
- // colors. Set it once here, in case the palette stays the same and update
- // it on each palette change by copySysPaletteToScreen().
- _remappingPercentToSet = percent;
-
- for (int i = 0; i < 256; i++) {
- byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100;
- byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100;
- byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100;
- _remappingByPercent[i] = kernelFindColor(r, g, b);
- }
-
- _remappingType[color] = kRemappingByPercent;
-}
-
-void GfxPalette::setRemappingPercentGray(byte color, byte percent) {
- _remapOn = true;
-
- // We need to defer the setup of the remapping table every time the screen
- // palette is changed, so that kernelFindColor() can find the correct
- // colors. Set it once here, in case the palette stays the same and update
- // it on each palette change by copySysPaletteToScreen().
- _remappingPercentToSet = percent;
-
- // Note: This is not what the original does, but the results are the same visually
- for (int i = 0; i < 256; i++) {
- byte rComponent = (byte)(_sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100);
- byte gComponent = (byte)(_sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100);
- byte bComponent = (byte)(_sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100);
- byte luminosity = rComponent + gComponent + bComponent;
- _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity);
- }
-
- _remappingType[color] = kRemappingByPercent;
-}
-
-void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) {
- _remapOn = true;
-
- for (int i = from; i <= to; i++) {
- _remappingByRange[i] = i + base;
- }
-
- _remappingType[color] = kRemappingByRange;
-}
-
bool GfxPalette::insert(Palette *newPalette, Palette *destPalette) {
bool paletteChanged = false;
@@ -589,15 +514,8 @@ void GfxPalette::copySysPaletteToScreen() {
}
}
- // Check if we need to reset remapping by percent with the new colors.
- if (_remappingPercentToSet) {
- for (int i = 0; i < 256; i++) {
- byte r = _sysPalette.colors[i].r * _remappingPercentToSet / 100;
- byte g = _sysPalette.colors[i].g * _remappingPercentToSet / 100;
- byte b = _sysPalette.colors[i].b * _remappingPercentToSet / 100;
- _remappingByPercent[i] = kernelFindColor(r, g, b);
- }
- }
+ if (g_sci->_gfxRemap16)
+ g_sci->_gfxRemap16->updateRemapping();
g_system->getPaletteManager()->setPalette(bpal, 0, 256);
}
diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h
index 61a8d36cb9..2178de8a91 100644
--- a/engines/sci/graphics/palette.h
+++ b/engines/sci/graphics/palette.h
@@ -35,12 +35,6 @@ class GfxScreen;
#define SCI_PALETTE_MATCH_PERFECT 0x8000
#define SCI_PALETTE_MATCH_COLORMASK 0xFF
-enum ColorRemappingType {
- kRemappingNone = 0,
- kRemappingByRange = 1,
- kRemappingByPercent = 2
-};
-
/**
* Palette class, handles palette operations like changing intensity, setting up the palette, merging different palettes
*/
@@ -57,32 +51,23 @@ public:
bool setAmiga();
void modifyAmigaPalette(byte *data);
void setEGA();
- virtual void set(Palette *sciPal, bool force, bool forceRealMerge = false);
+ void set(Palette *sciPal, bool force, bool forceRealMerge = false);
bool insert(Palette *newPalette, Palette *destPalette);
bool merge(Palette *pFrom, bool force, bool forceRealMerge);
uint16 matchColor(byte r, byte g, byte b);
void getSys(Palette *pal);
uint16 getTotalColorCount() const { return _totalScreenColors; }
- void resetRemapping();
- void setRemappingPercent(byte color, byte percent);
- void setRemappingPercentGray(byte color, byte percent);
- void setRemappingRange(byte color, byte from, byte to, byte base);
- bool isRemapped(byte color) const {
- return _remapOn && (_remappingType[color] != kRemappingNone);
- }
- byte remapColor(byte remappedColor, byte screenColor);
-
void setOnScreen();
void copySysPaletteToScreen();
void drewPicture(GuiResourceId pictureId);
- virtual bool kernelSetFromResource(GuiResourceId resourceId, bool force);
+ bool kernelSetFromResource(GuiResourceId resourceId, bool force);
void kernelSetFlag(uint16 fromColor, uint16 toColor, uint16 flag);
void kernelUnsetFlag(uint16 fromColor, uint16 toColor, uint16 flag);
void kernelSetIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette);
- virtual int16 kernelFindColor(uint16 r, uint16 g, uint16 b);
+ int16 kernelFindColor(uint16 r, uint16 g, uint16 b);
bool kernelAnimate(byte fromColor, byte toColor, int speed);
void kernelAnimateSet();
reg_t kernelSave();
@@ -96,7 +81,7 @@ public:
int16 kernelPalVaryGetCurrentStep();
int16 kernelPalVaryChangeTarget(GuiResourceId resourceId);
void kernelPalVaryChangeTicks(uint16 ticks);
- virtual void kernelPalVaryPause(bool pause);
+ void kernelPalVaryPause(bool pause);
void kernelPalVaryDeinit();
void palVaryUpdate();
void palVaryPrepareForTransition();
@@ -104,7 +89,7 @@ public:
Palette _sysPalette;
- virtual void saveLoadWithSerializer(Common::Serializer &s);
+ void saveLoadWithSerializer(Common::Serializer &s);
void palVarySaveLoadPalette(Common::Serializer &s, Palette *palette);
byte findMacIconBarColor(byte r, byte g, byte b);
@@ -138,12 +123,6 @@ protected:
int _palVarySignal;
uint16 _totalScreenColors;
- bool _remapOn;
- ColorRemappingType _remappingType[256];
- byte _remappingByPercent[256];
- byte _remappingByRange[256];
- uint16 _remappingPercentToSet;
-
void loadMacIconBarPalette();
byte *_macClut;
};
diff --git a/engines/sci/graphics/palette32.cpp b/engines/sci/graphics/palette32.cpp
index 9204e4bf96..2a98c237b0 100644
--- a/engines/sci/graphics/palette32.cpp
+++ b/engines/sci/graphics/palette32.cpp
@@ -27,18 +27,109 @@
#include "sci/sci.h"
#include "sci/event.h"
#include "sci/resource.h"
+#include "sci/util.h"
#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
#include "sci/graphics/screen.h"
namespace Sci {
-GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen)
- : GfxPalette(resMan, screen),
+#pragma mark HunkPalette
+
+HunkPalette::HunkPalette(byte *rawPalette) :
+ _version(0),
+ // NOTE: The header size in palettes is garbage. In at least KQ7 2.00b and
+ // Phant1, the 999.pal sets this value to 0. In most other palettes it is
+ // set to 14, but the *actual* size of the header structure used in SSCI is
+ // 13, which is reflected by `kHunkPaletteHeaderSize`.
+ // _headerSize(rawPalette[0]),
+ _numPalettes(rawPalette[10]),
+ _data(nullptr) {
+ assert(_numPalettes == 0 || _numPalettes == 1);
+ if (_numPalettes) {
+ _data = rawPalette;
+ _version = getEntryHeader().version;
+ }
+}
+
+void HunkPalette::setVersion(const uint32 version) {
+ if (_numPalettes != _data[10]) {
+ error("Invalid HunkPalette");
+ }
+
+ if (_numPalettes) {
+ const EntryHeader header = getEntryHeader();
+ if (header.version != _version) {
+ error("Invalid HunkPalette");
+ }
+
+ WRITE_SCI11ENDIAN_UINT32(getPalPointer() + kEntryVersionOffset, version);
+ _version = version;
+ }
+}
+
+const HunkPalette::EntryHeader HunkPalette::getEntryHeader() const {
+ const byte *const data = getPalPointer();
+
+ EntryHeader header;
+ header.startColor = data[10];
+ header.numColors = READ_SCI11ENDIAN_UINT16(data + 14);
+ header.used = data[16];
+ header.sharedUsed = data[17];
+ header.version = READ_SCI11ENDIAN_UINT32(data + kEntryVersionOffset);
+
+ return header;
+}
+
+const Palette HunkPalette::toPalette() const {
+ Palette outPalette;
+
+ for (int16 i = 0; i < ARRAYSIZE(outPalette.colors); ++i) {
+ outPalette.colors[i].used = false;
+ outPalette.colors[i].r = 0;
+ outPalette.colors[i].g = 0;
+ outPalette.colors[i].b = 0;
+ }
+
+ if (_numPalettes) {
+ const EntryHeader header = getEntryHeader();
+ byte *data = getPalPointer() + kEntryHeaderSize;
+
+ int16 end = header.startColor + header.numColors;
+ assert(end <= 256);
+
+ if (header.sharedUsed) {
+ for (int16 i = header.startColor; i < end; ++i) {
+ outPalette.colors[i].used = header.used;
+ outPalette.colors[i].r = *data++;
+ outPalette.colors[i].g = *data++;
+ outPalette.colors[i].b = *data++;
+ }
+ } else {
+ for (int16 i = header.startColor; i < end; ++i) {
+ outPalette.colors[i].used = *data++;
+ outPalette.colors[i].r = *data++;
+ outPalette.colors[i].g = *data++;
+ outPalette.colors[i].b = *data++;
+ }
+ }
+ }
+
+ return outPalette;
+}
+
+
+#pragma mark -
+#pragma mark GfxPalette32
+
+GfxPalette32::GfxPalette32(ResourceManager *resMan)
+ : _resMan(resMan),
// Palette versioning
_version(1),
- _versionUpdated(false),
- _sourcePalette(_sysPalette),
- _nextPalette(_sysPalette),
+ _needsUpdate(false),
+ _currentPalette(),
+ _sourcePalette(),
+ _nextPalette(),
// Clut
_clutTable(nullptr),
// Palette varying
@@ -54,104 +145,91 @@ GfxPalette32::GfxPalette32(ResourceManager *resMan, GfxScreen *screen)
// Palette cycling
_cyclers(),
_cycleMap() {
- _varyPercent = _varyTargetPercent;
- memset(_fadeTable, 100, sizeof(_fadeTable));
- // NOTE: In SCI engine, the palette manager constructor loads
- // the default palette, but in ScummVM this initialisation
- // is performed by SciEngine::run; see r49523 for details
+ _varyPercent = _varyTargetPercent;
+ for (int i = 0, len = ARRAYSIZE(_fadeTable); i < len; ++i) {
+ _fadeTable[i] = 100;
+ }
+
+ loadPalette(999);
}
GfxPalette32::~GfxPalette32() {
+#ifdef ENABLE_SCI3_GAMES
unloadClut();
+#endif
varyOff();
cycleAllOff();
}
inline void mergePaletteInternal(Palette *const to, const Palette *const from) {
- for (int i = 0; i < ARRAYSIZE(to->colors); ++i) {
+ // The last color is always white, so it is not copied.
+ // (Some palettes try to set the last color, which causes
+ // churning in the palettes when they are merged)
+ for (int i = 0, len = ARRAYSIZE(to->colors) - 1; i < len; ++i) {
if (from->colors[i].used) {
to->colors[i] = from->colors[i];
}
}
}
-const Palette *GfxPalette32::getNextPalette() const {
- return &_nextPalette;
+void GfxPalette32::submit(const Palette &palette) {
+ const Palette oldSourcePalette(_sourcePalette);
+ mergePaletteInternal(&_sourcePalette, &palette);
+
+ if (!_needsUpdate && _sourcePalette != oldSourcePalette) {
+ ++_version;
+ _needsUpdate = true;
+ }
}
-void GfxPalette32::submit(Palette &palette) {
- // TODO: The resource manager in SCI32 retains raw data of palettes from
- // the ResourceManager (ResourceMgr) through SegManager (MemoryMgr), and
- // the version number for submitted palettes is set in the raw palette
- // data in memory as an int at an offset
- // `rawData + *rawData[0x0a] * 2 + 31`. However, ScummVM does not retain
- // resource data like this, so this versioning code, while accurate to
- // the original engine, does not do much.
- // (Hopefully this was an optimisation mechanism in SCI engine and not a
- // clever thing to keep the same palette submitted many times from
- // overwriting other palette entries.)
- if (palette.timestamp == _version) {
+void GfxPalette32::submit(HunkPalette &hunkPalette) {
+ if (hunkPalette.getVersion() == _version) {
return;
}
- Palette oldSourcePalette(_sourcePalette);
+ const Palette oldSourcePalette(_sourcePalette);
+ const Palette palette = hunkPalette.toPalette();
mergePaletteInternal(&_sourcePalette, &palette);
- if (!_versionUpdated && _sourcePalette != oldSourcePalette) {
+ if (!_needsUpdate && oldSourcePalette != _sourcePalette) {
++_version;
- _versionUpdated = true;
+ _needsUpdate = true;
}
- // Technically this information is supposed to be persisted through a
- // HunkPalette object; right now it would just be lost once the temporary
- // palette was destroyed.
- palette.timestamp = _version;
+ hunkPalette.setVersion(_version);
}
-bool GfxPalette32::kernelSetFromResource(GuiResourceId resourceId, bool force) {
- // TODO: In SCI32, palettes that come from resources come in as
- // HunkPalette objects, not SOLPalette objects. The HunkPalettes
- // have some extra persistence stuff associated with them, such that
- // when they are passed to GfxPalette32::submit, they would get the
- // version number of GfxPalette32 assigned to them.
- Palette palette;
+bool GfxPalette32::loadPalette(const GuiResourceId resourceId) {
+ Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
- if (createPaletteFromResourceInternal(resourceId, &palette)) {
- submit(palette);
- return true;
+ if (!palResource) {
+ return false;
}
- return false;
+ HunkPalette palette(palResource->data);
+ submit(palette);
+ return true;
}
-// In SCI32 engine this method is SOLPalette::Match(Rgb24 *)
-// and is called as PaletteMgr.Current().Match(color)
-int16 GfxPalette32::kernelFindColor(uint16 r, uint16 g, uint16 b) {
- // SQ6 SCI32 engine takes the 16-bit r, g, b arguments from the
- // VM and puts them into al, ah, dl. For compatibility, make sure
- // to discard any high bits here too
- r = r & 0xFF;
- g = g & 0xFF;
- b = b & 0xFF;
+int16 GfxPalette32::matchColor(const uint8 r, const uint8 g, const uint8 b) {
int16 bestIndex = 0;
int bestDifference = 0xFFFFF;
int difference;
- // SQ6 DOS really does check only the first 236 entries
- for (int i = 0, channelDifference; i < 236; ++i) {
- difference = _sysPalette.colors[i].r - r;
+ for (int i = 0, channelDifference; i < g_sci->_gfxRemap32->getStartColor(); ++i) {
+ difference = _currentPalette.colors[i].r - r;
difference *= difference;
if (bestDifference <= difference) {
continue;
}
- channelDifference = _sysPalette.colors[i].g - g;
+ channelDifference = _currentPalette.colors[i].g - g;
difference += channelDifference * channelDifference;
if (bestDifference <= difference) {
continue;
}
- channelDifference = _sysPalette.colors[i].b - b;
+ channelDifference = _currentPalette.colors[i].b - b;
difference += channelDifference * channelDifference;
if (bestDifference <= difference) {
continue;
@@ -163,102 +241,56 @@ int16 GfxPalette32::kernelFindColor(uint16 r, uint16 g, uint16 b) {
return bestIndex;
}
-// TODO: set is overridden for the time being to send palettes coming from
-// various draw methods like GfxPicture::drawSci32Vga and GfxView::draw to
-// _nextPalette instead of _sysPalette. In the SCI32 engine, CelObj palettes
-// (which are stored as Hunk palettes) are submitted by GraphicsMgr::FrameOut
-// to PaletteMgr::Submit by way of calls to CelObj::SubmitPalette.
-// GfxPalette::set is very similar to GfxPalette32::submit, except that SCI32
-// does not do any fancy best-fit merging and so does not accept arguments
-// like `force` and `forceRealMerge`.
-void GfxPalette32::set(Palette *newPalette, bool force, bool forceRealMerge) {
- submit(*newPalette);
-}
-
-// In SCI32 engine this method is SOLPalette::Match(Rgb24 *, int, int *, int *)
-// and is used by Remap
-// TODO: Anything that calls GfxPalette::matchColor(int, int, int) is going to
-// match using an algorithm from SCI16 engine right now. This needs to be
-// corrected in the future so either nothing calls
-// GfxPalette::matchColor(int, int, int), or it is fixed to match the other
-// SCI32 algorithms.
-int16 GfxPalette32::matchColor(const byte r, const byte g, const byte b, const int defaultDifference, int &lastCalculatedDifference, const bool *const matchTable) {
- int16 bestIndex = -1;
- int bestDifference = 0xFFFFF;
- int difference = defaultDifference;
-
- // SQ6 DOS really does check only the first 236 entries
- for (int i = 0, channelDifference; i < 236; ++i) {
- if (matchTable[i] == 0) {
- continue;
- }
-
- difference = _sysPalette.colors[i].r - r;
- difference *= difference;
- if (bestDifference <= difference) {
- continue;
- }
- channelDifference = _sysPalette.colors[i].g - g;
- difference += channelDifference * channelDifference;
- if (bestDifference <= difference) {
- continue;
- }
- channelDifference = _sysPalette.colors[i].b - b;
- difference += channelDifference * channelDifference;
- if (bestDifference <= difference) {
- continue;
- }
- bestDifference = difference;
- bestIndex = i;
- }
-
- // NOTE: This value is only valid if the last index to
- // perform a difference calculation was the best index
- lastCalculatedDifference = difference;
- return bestIndex;
-}
-
bool GfxPalette32::updateForFrame() {
applyAll();
- _versionUpdated = false;
- // TODO: Implement remapping
- // return g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
- return false;
+ _needsUpdate = false;
+ return g_sci->_gfxRemap32->remapAllTables(_nextPalette != _currentPalette);
}
void GfxPalette32::updateFFrame() {
for (int i = 0; i < ARRAYSIZE(_nextPalette.colors); ++i) {
_nextPalette.colors[i] = _sourcePalette.colors[i];
}
- _versionUpdated = false;
- // TODO: Implement remapping
- // g_sci->_gfxFrameout->remapAllTables(_nextPalette != _sysPalette);
+ _needsUpdate = false;
+ g_sci->_gfxRemap32->remapAllTables(_nextPalette != _currentPalette);
}
-void GfxPalette32::updateHardware() {
- if (_sysPalette == _nextPalette) {
+void GfxPalette32::updateHardware(const bool updateScreen) {
+ if (_currentPalette == _nextPalette) {
return;
}
byte bpal[3 * 256];
- for (int i = 0; i < ARRAYSIZE(_sysPalette.colors); ++i) {
- _sysPalette.colors[i] = _nextPalette.colors[i];
+ for (int i = 0; i < ARRAYSIZE(_currentPalette.colors) - 1; ++i) {
+ _currentPalette.colors[i] = _nextPalette.colors[i];
// NOTE: If the brightness option in the user configuration file is set,
// SCI engine adjusts palette brightnesses here by mapping RGB values to values
// in some hard-coded brightness tables. There is no reason on modern hardware
// to implement this, unless it is discovered that some game uses a non-standard
// brightness setting by default
- if (_sysPalette.colors[i].used) {
- bpal[i * 3 ] = _sysPalette.colors[i].r;
- bpal[i * 3 + 1] = _sysPalette.colors[i].g;
- bpal[i * 3 + 2] = _sysPalette.colors[i].b;
- }
+
+ // All color entries MUST be copied, not just "used" entries, otherwise
+ // uninitialised memory from bpal makes its way into the system palette.
+ // This would not normally be a problem, except that games sometimes use
+ // unused palette entries. e.g. Phant1 title screen references palette
+ // entries outside its own palette, so will render garbage colors where
+ // the game expects them to be black
+ bpal[i * 3 ] = _currentPalette.colors[i].r;
+ bpal[i * 3 + 1] = _currentPalette.colors[i].g;
+ bpal[i * 3 + 2] = _currentPalette.colors[i].b;
}
+ // The last color must always be white
+ bpal[255 * 3 ] = 255;
+ bpal[255 * 3 + 1] = 255;
+ bpal[255 * 3 + 2] = 255;
+
g_system->getPaletteManager()->setPalette(bpal, 0, 256);
- g_sci->getEventManager()->updateScreen();
+ if (updateScreen) {
+ g_sci->getEventManager()->updateScreen();
+ }
}
void GfxPalette32::applyAll() {
@@ -270,6 +302,7 @@ void GfxPalette32::applyAll() {
#pragma mark -
#pragma mark Colour look-up
+#ifdef ENABLE_SCI3_GAMES
bool GfxPalette32::loadClut(uint16 clutId) {
// loadClut() will load a color lookup table from a clu file and set
// the palette found in the file. This is to be used with Phantasmagoria 2.
@@ -319,27 +352,20 @@ void GfxPalette32::unloadClut() {
delete[] _clutTable;
_clutTable = nullptr;
}
+#endif
#pragma mark -
#pragma mark Varying
-inline bool GfxPalette32::createPaletteFromResourceInternal(const GuiResourceId paletteId, Palette *const out) const {
- Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, paletteId), false);
+inline Palette GfxPalette32::getPaletteFromResourceInternal(const GuiResourceId resourceId) const {
+ Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), false);
if (!palResource) {
- return false;
+ error("Could not load vary palette %d", resourceId);
}
- createFromData(palResource->data, palResource->size, out);
- return true;
-}
-
-inline Palette GfxPalette32::getPaletteFromResourceInternal(const GuiResourceId paletteId) const {
- Palette palette;
- if (!createPaletteFromResourceInternal(paletteId, &palette)) {
- error("Could not load vary target %d", paletteId);
- }
- return palette;
+ HunkPalette rawPalette(palResource->data);
+ return rawPalette.toPalette();
}
inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int time) {
@@ -363,8 +389,6 @@ inline void GfxPalette32::setVaryTimeInternal(const int16 percent, const int tim
}
}
-// TODO: This gets called *a lot* in at least the first scene
-// of SQ6. Optimisation would not be the worst idea in the world.
void GfxPalette32::kernelPalVarySet(const GuiResourceId paletteId, const int16 percent, const int time, const int16 fromColor, const int16 toColor) {
Palette palette = getPaletteFromResourceInternal(paletteId);
setVary(&palette, percent, time, fromColor, toColor);
@@ -632,18 +656,15 @@ void GfxPalette32::setCycle(const uint8 fromColor, const uint8 toColor, const in
// SCI engine overrides the first oldest cycler that it finds where
// “oldest†is determined by the difference between the tick and now
if (cycler == nullptr) {
- int maxUpdateDelta = -1;
- // Optimization: Unlike actual SCI (SQ6) engine, we call
- // getTickCount only once and store it, instead of calling it
- // twice on each iteration through the loop
const uint32 now = g_sci->getTickCount();
+ uint32 minUpdateDelta = 0xFFFFFFFF;
for (cyclerIndex = 0; cyclerIndex < numCyclers; ++cyclerIndex) {
PalCycler *candidate = _cyclers[cyclerIndex];
- const int32 updateDelta = now - candidate->lastUpdateTick;
- if (updateDelta >= maxUpdateDelta) {
- maxUpdateDelta = updateDelta;
+ const uint32 updateDelta = now - candidate->lastUpdateTick;
+ if (updateDelta < minUpdateDelta) {
+ minUpdateDelta = updateDelta;
cycler = candidate;
}
}
@@ -695,14 +716,8 @@ void GfxPalette32::cycleAllOn() {
}
void GfxPalette32::cycleAllPause() {
- // TODO: The SCI SQ6 cycleAllPause function does not seem to perform
- // nullptr checking?? This would definitely cause null pointer
- // dereference in SCI code. I have not seen anything actually call
- // this function yet, so it is possible it is just unused and broken
- // in SCI SQ6. This assert exists so that if this function is called,
- // it is noticed and can be rechecked in the actual engine.
- // Obviously this code *does* do nullptr checks instead of crashing. :)
- assert(0);
+ // NOTE: The original engine did not check for null pointers in the
+ // palette cyclers pointer array.
for (int i = 0, len = ARRAYSIZE(_cyclers); i < len; ++i) {
PalCycler *cycler = _cyclers[i];
if (cycler != nullptr) {
@@ -795,7 +810,7 @@ void GfxPalette32::applyCycles() {
// the last palette entry is intentionally left unmodified, or if this is a bug
// in the engine. It certainly seems confused because all other places that accept
// color ranges typically receive values in the range of 0–255.
-void GfxPalette32::setFade(uint8 percent, uint8 fromColor, uint16 numColorsToFade) {
+void GfxPalette32::setFade(uint16 percent, uint8 fromColor, uint16 numColorsToFade) {
if (fromColor > numColorsToFade) {
return;
}
@@ -817,9 +832,10 @@ void GfxPalette32::applyFade() {
Color &color = _nextPalette.colors[i];
- color.r = (int16)color.r * _fadeTable[i] / 100;
- color.g = (int16)color.g * _fadeTable[i] / 100;
- color.b = (int16)color.b * _fadeTable[i] / 100;
+ color.r = MIN(255, (uint16)color.r * _fadeTable[i] / 100);
+ color.g = MIN(255, (uint16)color.g * _fadeTable[i] / 100);
+ color.b = MIN(255, (uint16)color.b * _fadeTable[i] / 100);
}
}
-}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/palette32.h b/engines/sci/graphics/palette32.h
index 9da217bf31..dc2158022f 100644
--- a/engines/sci/graphics/palette32.h
+++ b/engines/sci/graphics/palette32.h
@@ -26,6 +26,118 @@
#include "sci/graphics/palette.h"
namespace Sci {
+
+/**
+ * HunkPalette represents a raw palette resource
+ * read from disk.
+ */
+class HunkPalette {
+public:
+ HunkPalette(byte *rawPalette);
+
+ /**
+ * Gets the version of the palette.
+ */
+ uint32 getVersion() const { return _version; }
+
+ /**
+ * Sets the version of the palette.
+ */
+ void setVersion(const uint32 version);
+
+ /**
+ * Converts the hunk palette to a standard
+ * palette.
+ */
+ const Palette toPalette() const;
+
+private:
+ enum {
+ /**
+ * The size of the HunkPalette header.
+ */
+ kHunkPaletteHeaderSize = 13,
+
+ /**
+ * The size of a palette entry header.
+ */
+ kEntryHeaderSize = 22,
+
+ /**
+ * The offset of the hunk palette version
+ * within the palette entry header.
+ */
+ kEntryVersionOffset = 18
+ };
+
+ /**
+ * The header for a palette inside the
+ * HunkPalette.
+ */
+ struct EntryHeader {
+ /**
+ * The start color.
+ */
+ uint8 startColor;
+
+ /**
+ * The number of palette colors in this
+ * entry.
+ */
+ uint16 numColors;
+
+ /**
+ * The default `used` flag.
+ */
+ bool used;
+
+ /**
+ * Whether or not all palette entries
+ * share the same `used` value in
+ * `defaultFlag`.
+ */
+ bool sharedUsed;
+
+ /**
+ * The palette version.
+ */
+ uint32 version;
+ };
+
+ /**
+ * The version number from the last time this
+ * palette was submitted to GfxPalette32.
+ */
+ uint32 _version;
+
+ /**
+ * The number of palettes stored in the hunk
+ * palette. In SCI32 games this is always 1.
+ */
+ uint8 _numPalettes;
+
+ /**
+ * The raw palette data for this hunk palette.
+ */
+ byte *_data;
+
+ /**
+ * Returns a struct that describes the palette
+ * held by this HunkPalette. The entry header
+ * is reconstructed on every call from the raw
+ * palette data.
+ */
+ const EntryHeader getEntryHeader() const;
+
+ /**
+ * Returns a pointer to the palette data within
+ * the hunk palette.
+ */
+ byte *getPalPointer() const {
+ return _data + kHunkPaletteHeaderSize + (2 * _numPalettes);
+ }
+};
+
enum PalCyclerDirection {
PalCycleBackward = 0,
PalCycleForward = 1
@@ -72,28 +184,29 @@ struct PalCycler {
uint16 numTimesPaused;
};
-class GfxPalette32 : public GfxPalette {
+class GfxPalette32 {
public:
- GfxPalette32(ResourceManager *resMan, GfxScreen *screen);
+ GfxPalette32(ResourceManager *resMan);
~GfxPalette32();
private:
- // NOTE: currentPalette in SCI engine is called _sysPalette
- // here.
+ ResourceManager *_resMan;
/**
* The palette revision version. Increments once per game
- * loop that changes the source palette. TODO: Possibly
- * other areas also change _version, double-check once it
- * is all implemented.
+ * loop that changes the source palette.
*/
uint32 _version;
/**
- * Whether or not the palette manager version was updated
- * during this loop.
+ * Whether or not the hardware palette needs updating.
*/
- bool _versionUpdated;
+ bool _needsUpdate;
+
+ /**
+ * The currently displayed palette.
+ */
+ Palette _currentPalette;
/**
* The unmodified source palette loaded by kPalette. Additional
@@ -104,7 +217,7 @@ private:
/**
* The palette to be used when the hardware is next updated.
- * On update, _nextPalette is transferred to _sysPalette.
+ * On update, _nextPalette is transferred to _currentPalette.
*/
Palette _nextPalette;
@@ -112,28 +225,37 @@ private:
Palette getPaletteFromResourceInternal(const GuiResourceId paletteId) const;
public:
- virtual void saveLoadWithSerializer(Common::Serializer &s) override;
- const Palette *getNextPalette() const;
+ void saveLoadWithSerializer(Common::Serializer &s);
+ inline const Palette &getNextPalette() const { return _nextPalette; };
+ inline const Palette &getCurrentPalette() const { return _currentPalette; };
- bool kernelSetFromResource(GuiResourceId resourceId, bool force) override;
- int16 kernelFindColor(uint16 r, uint16 g, uint16 b) override;
- void set(Palette *newPalette, bool force, bool forceRealMerge = false) override;
- int16 matchColor(const byte matchRed, const byte matchGreen, const byte matchBlue, const int defaultDifference, int &lastCalculatedDifference, const bool *const matchTable);
+ /**
+ * Loads a palette into GfxPalette32 with the given resource
+ * ID.
+ */
+ bool loadPalette(const GuiResourceId resourceId);
+
+ /**
+ * Finds the nearest color in the current palette matching the
+ * given RGB value.
+ */
+ int16 matchColor(const uint8 r, const uint8 g, const uint8 b);
/**
* Submits a palette to display. Entries marked as “used†in the
* submitted palette are merged into the existing entries of
* _sourcePalette.
*/
- void submit(Palette &palette);
+ void submit(const Palette &palette);
+ void submit(HunkPalette &palette);
bool updateForFrame();
void updateFFrame();
- void updateHardware();
+ void updateHardware(const bool updateScreen = true);
void applyAll();
#pragma mark -
-#pragma mark color look-up
+#pragma mark Color look-up
private:
/**
* An optional lookup table used to remap RGB565 colors to a palette
@@ -213,7 +335,7 @@ public:
void kernelPalVarySetTarget(const GuiResourceId paletteId);
void kernelPalVarySetStart(const GuiResourceId paletteId);
void kernelPalVaryMergeStart(const GuiResourceId paletteId);
- virtual void kernelPalVaryPause(bool pause) override;
+ void kernelPalVaryPause(bool pause);
void setVary(const Palette *const targetPalette, const int16 percent, const int time, const int16 fromColor, const int16 toColor);
void setVaryPercent(const int16 percent, const int time, const int16 fromColor, const int16 fromColorAlternate);
@@ -240,6 +362,11 @@ private:
* According to SCI engine code, when two cyclers overlap,
* a fatal error has occurred and the engine will display
* an error and then exit.
+ *
+ * The cycle map is also by the color remapping system to
+ * avoid attempting to remap to palette entries that are
+ * cycling (so won't be the expected color once the cycler
+ * runs again).
*/
bool _cycleMap[256];
inline void clearCycleMap(uint16 fromColor, uint16 numColorsToClear);
@@ -257,6 +384,7 @@ public:
void cycleAllOff();
void applyAllCycles();
void applyCycles();
+ inline const bool *getCycleMap() const { return _cycleMap; }
#pragma mark -
#pragma mark Fading
@@ -265,13 +393,19 @@ private:
* The fade table records the expected intensity level of each pixel
* in the palette that will be displayed on the next frame.
*/
- byte _fadeTable[256];
+ uint16 _fadeTable[256];
public:
- void setFade(const uint8 percent, const uint8 fromColor, const uint16 toColor);
+ /**
+ * Sets the intensity level for a range of palette
+ * entries. An intensity of zero indicates total
+ * darkness. Intensity may be set to over 100 percent.
+ */
+ void setFade(const uint16 percent, const uint8 fromColor, const uint16 toColor);
void fadeOff();
void applyFade();
};
-}
+
+} // End of namespace Sci
#endif
diff --git a/engines/sci/graphics/plane32.cpp b/engines/sci/graphics/plane32.cpp
index d0de5b5917..aa629e4081 100644
--- a/engines/sci/graphics/plane32.cpp
+++ b/engines/sci/graphics/plane32.cpp
@@ -27,6 +27,7 @@
#include "sci/graphics/frameout.h"
#include "sci/graphics/lists32.h"
#include "sci/graphics/plane32.h"
+#include "sci/graphics/remap32.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/screen_item32.h"
@@ -43,11 +44,10 @@ void DrawList::add(ScreenItem *screenItem, const Common::Rect &rect) {
#pragma mark Plane
uint16 Plane::_nextObjectId = 20000;
-Plane::Plane(const Common::Rect &gameRect) :
-_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
-_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
-_pictureId(kPlanePicColored),
+Plane::Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId) :
+_pictureId(pictureId),
_mirrored(false),
+_type(kPlaneTypeColored),
_back(0),
_priorityChanged(0),
_object(make_reg(0, _nextObjectId++)),
@@ -55,6 +55,7 @@ _redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
+_moved(0),
_gameRect(gameRect) {
convertGameRectToPlaneRect();
_priority = MAX(10000, g_sci->_gfxFrameout->getPlanes().getTopPlanePriority() + 1);
@@ -63,8 +64,7 @@ _gameRect(gameRect) {
}
Plane::Plane(reg_t object) :
-_width(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
-_height(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
+_type(kPlaneTypeColored),
_priorityChanged(false),
_object(object),
_redrawAllCount(g_sci->_gfxFrameout->getScreenCount()),
@@ -95,8 +95,7 @@ _moved(0) {
Plane::Plane(const Plane &other) :
_pictureId(other._pictureId),
_mirrored(other._mirrored),
-_field_34(other._field_34), _field_38(other._field_38),
-_field_3C(other._field_3C), _field_40(other._field_40),
+_type(other._type),
_back(other._back),
_object(other._object),
_priority(other._priority),
@@ -114,11 +113,7 @@ void Plane::operator=(const Plane &other) {
_mirrored = other._mirrored;
_priority = other._priority;
_back = other._back;
- _width = other._width;
- _field_34 = other._field_34;
- _height = other._height;
_screenRect = other._screenRect;
- _field_3C = other._field_3C;
_priorityChanged = other._priorityChanged;
}
@@ -136,7 +131,7 @@ void Plane::convertGameRectToPlaneRect() {
const Ratio ratioY = Ratio(screenHeight, scriptHeight);
_planeRect = _gameRect;
- mulru(_planeRect, ratioX, ratioY);
+ mulru(_planeRect, ratioX, ratioY, 1);
}
void Plane::printDebugInfo(Console *con) const {
@@ -171,17 +166,21 @@ void Plane::printDebugInfo(Console *con) const {
void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX) {
uint16 celCount = 1000;
+ bool transparent = true;
for (uint16 celNo = 0; celNo < celCount; ++celNo) {
CelObjPic *celObj = new CelObjPic(pictureId, celNo);
if (celCount == 1000) {
celCount = celObj->_celCount;
}
+ if (!celObj->_transparent) {
+ transparent = false;
+ }
ScreenItem *screenItem = new ScreenItem(_object, celObj->_info);
screenItem->_pictureId = pictureId;
screenItem->_mirrorX = mirrorX;
screenItem->_priority = celObj->_priority;
- screenItem->_fixPriority = true;
+ screenItem->_fixedPriority = true;
if (position != nullptr) {
screenItem->_position = *position + celObj->_relativePosition;
} else {
@@ -192,6 +191,7 @@ void Plane::addPicInternal(const GuiResourceId pictureId, const Common::Point *p
delete screenItem->_celObj;
screenItem->_celObj = celObj;
}
+ _type = transparent ? kPlaneTypeTransparentPicture : kPlaneTypePicture;
}
void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX) {
@@ -204,7 +204,7 @@ void Plane::addPic(const GuiResourceId pictureId, const Common::Point &position,
void Plane::changePic() {
_pictureChanged = false;
- if (_type != kPlaneTypePicture) {
+ if (_type != kPlaneTypePicture && _type != kPlaneTypeTransparentPicture) {
return;
}
@@ -248,16 +248,20 @@ void Plane::deleteAllPics() {
#pragma mark Plane - Rendering
void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const {
- int index = planeList.findIndexByObject(_object);
+ const int nextPlaneIndex = planeList.findIndexByObject(_object) + 1;
+ const PlaneList::size_type planeCount = planeList.size();
for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
- for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) {
- if (planeList[j]->_type != kPlaneTypeTransparent) {
- Common::Rect ptr[4];
- int count = splitRects(drawList[i]->rect, planeList[j]->_screenRect, ptr);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- drawList.add(drawList[i]->screenItem, ptr[k]);
+ for (PlaneList::size_type j = nextPlaneIndex; j < planeCount; ++j) {
+ if (
+ planeList[j]->_type != kPlaneTypeTransparent &&
+ planeList[j]->_type != kPlaneTypeTransparentPicture
+ ) {
+ Common::Rect outRects[4];
+ int splitCount = splitRects(drawList[i]->rect, planeList[j]->_screenRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ drawList.add(drawList[i]->screenItem, outRects[splitCount]);
}
drawList.erase_at(i);
@@ -270,17 +274,20 @@ void Plane::breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList
}
void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const {
- int index = planeList.findIndexByObject(_object);
+ const int nextPlaneIndex = planeList.findIndexByObject(_object) + 1;
+ const PlaneList::size_type planeCount = planeList.size();
for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- for (PlaneList::size_type j = index + 1; j < planeList.size(); ++j) {
- if (planeList[j]->_type != kPlaneTypeTransparent) {
- Common::Rect ptr[4];
-
- int count = splitRects(*eraseList[i], planeList[j]->_screenRect, ptr);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- eraseList.add(ptr[k]);
+ for (PlaneList::size_type j = nextPlaneIndex; j < planeCount; ++j) {
+ if (
+ planeList[j]->_type != kPlaneTypeTransparent &&
+ planeList[j]->_type != kPlaneTypeTransparentPicture
+ ) {
+ Common::Rect outRects[4];
+ int splitCount = splitRects(*eraseList[i], planeList[j]->_screenRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ eraseList.add(outRects[splitCount]);
}
eraseList.erase_at(i);
@@ -293,85 +300,109 @@ void Plane::breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeLi
}
void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
- ScreenItemList::size_type planeItemCount = _screenItemList.size();
- ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size();
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ const ScreenItemList::size_type visiblePlaneItemCount = visiblePlane._screenItemList.size();
+
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ // Items can be added to ScreenItemList and we don't want to process
+ // those new items, but the list also can grow smaller, so we need
+ // to check that we are still within the upper bound of the list and
+ // quit if we aren't any more
+ if (i >= _screenItemList.size()) {
+ break;
+ }
+
+ ScreenItem *item = _screenItemList[i];
+ if (item == nullptr) {
+ continue;
+ }
- for (PlaneList::size_type i = 0; i < planeItemCount; ++i) {
- ScreenItem *vitem = nullptr;
// NOTE: The original engine used an array without bounds checking
// so could just get the visible screen item directly; we need to
// verify that the index is actually within the valid range for
// the visible plane before accessing the item to avoid a range
// error.
+ const ScreenItem *visibleItem = nullptr;
if (i < visiblePlaneItemCount) {
- vitem = visiblePlane._screenItemList[i];
+ visibleItem = visiblePlane._screenItemList[i];
}
- ScreenItem *item = _screenItemList[i];
- if (i < _screenItemList.size() && item != nullptr) {
- if (item->_deleted) {
- // add item's rect to erase list
- if (i < visiblePlane._screenItemList.size() && vitem != nullptr) {
- if (!vitem->_screenRect.isEmpty()) {
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
- mergeToRectList(vitem->_screenRect, eraseList);
- } else {
- eraseList.add(vitem->_screenRect);
- }
- }
- }
- } else if (item->_created) {
- // add item to draw list
- item->getCelObj();
- item->calcRects(*this);
-
- if(!item->_screenRect.isEmpty()) {
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps?
- drawList.add(item, item->_screenRect);
- mergeToRectList(item->_screenRect, eraseList);
- } else {
- drawList.add(item, item->_screenRect);
- }
+ // Keep erase rects for this screen item from drawing outside
+ // of its owner plane
+ Common::Rect visibleItemScreenRect;
+ if (visibleItem != nullptr) {
+ visibleItemScreenRect = visibleItem->_screenRect;
+ visibleItemScreenRect.clip(_screenRect);
+ }
+
+ if (item->_deleted) {
+ // Add item's rect to erase list
+ if (
+ visibleItem != nullptr &&
+ !visibleItemScreenRect.isEmpty()
+ ) {
+ if (g_sci->_gfxRemap32->getRemapCount()) {
+ mergeToRectList(visibleItemScreenRect, eraseList);
+ } else {
+ eraseList.add(visibleItemScreenRect);
}
- } else if (item->_updated) {
- // add old rect to erase list, new item to draw list
- item->getCelObj();
- item->calcRects(*this);
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // active remaps
- // if item and vitem don't overlap, ...
- if (item->_screenRect.isEmpty() ||
- i >= visiblePlaneItemCount ||
- vitem == nullptr ||
- vitem->_screenRect.isEmpty() ||
- !vitem->_screenRect.intersects(item->_screenRect)
- ) {
- // add item to draw list, and old rect to erase list
- if (!item->_screenRect.isEmpty()) {
- drawList.add(item, item->_screenRect);
- mergeToRectList(item->_screenRect, eraseList);
- }
- if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) {
- mergeToRectList(vitem->_screenRect, eraseList);
- }
- } else {
- // otherwise, add bounding box of old+new to erase list,
- // and item to draw list
-
- // TODO: This was changed from disasm, verify please!
- Common::Rect extendedScreenItem = vitem->_screenRect;
- extendedScreenItem.extend(item->_screenRect);
- drawList.add(item, item->_screenRect);
- mergeToRectList(extendedScreenItem, eraseList);
- }
+ }
+ }
+
+ if (!item->_created && !item->_updated) {
+ continue;
+ }
+
+ item->calcRects(*this);
+ const Common::Rect itemScreenRect(item->_screenRect);
+
+ if (item->_created) {
+ // Add item to draw list
+ if(!itemScreenRect.isEmpty()) {
+ if (g_sci->_gfxRemap32->getRemapCount()) {
+ drawList.add(item, itemScreenRect);
+ mergeToRectList(itemScreenRect, eraseList);
} else {
- // if no active remaps, just add item to draw list and old rect
- // to erase list
- if (!item->_screenRect.isEmpty()) {
- drawList.add(item, item->_screenRect);
+ drawList.add(item, itemScreenRect);
+ }
+ }
+ } else {
+ // Add old rect to erase list, new item to draw list
+
+ if (g_sci->_gfxRemap32->getRemapCount()) {
+ // If item and visibleItem don't overlap...
+ if (itemScreenRect.isEmpty() ||
+ visibleItem == nullptr ||
+ visibleItemScreenRect.isEmpty() ||
+ !visibleItemScreenRect.intersects(itemScreenRect)
+ ) {
+ // ...add item to draw list, and old rect to erase list...
+ if (!itemScreenRect.isEmpty()) {
+ drawList.add(item, itemScreenRect);
+ mergeToRectList(itemScreenRect, eraseList);
}
- if (i < visiblePlaneItemCount && vitem != nullptr && !vitem->_screenRect.isEmpty()) {
- eraseList.add(vitem->_screenRect);
+ if (visibleItem != nullptr && !visibleItemScreenRect.isEmpty()) {
+ mergeToRectList(visibleItemScreenRect, eraseList);
}
+ } else {
+ // ...otherwise, add bounding box of old+new to erase list,
+ // and item to draw list
+ Common::Rect extendedScreenRect = visibleItemScreenRect;
+ extendedScreenRect.extend(itemScreenRect);
+
+ drawList.add(item, itemScreenRect);
+ mergeToRectList(extendedScreenRect, eraseList);
+ }
+ } else {
+ // If no active remaps, just add item to draw list and old rect
+ // to erase list
+
+ // TODO: SCI3 update rects for VMD?
+ if (!itemScreenRect.isEmpty()) {
+ drawList.add(item, itemScreenRect);
+ }
+ if (visibleItem != nullptr && !visibleItemScreenRect.isEmpty()) {
+ eraseList.add(visibleItemScreenRect);
}
}
}
@@ -381,39 +412,47 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
breakEraseListByPlanes(eraseList, planeList);
breakDrawListByPlanes(drawList, planeList);
- if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"????
+ // We store the current size of the drawlist, as we want to loop
+ // over the currently inserted entries later.
+ DrawList::size_type drawListSizePrimary = drawList.size();
+ const RectList::size_type eraseListCount = eraseList.size();
+
+ // TODO: Figure out which games need which rendering method
+ if (/* TODO: dword_C6288 */ false) { // "high resolution pictures"
_screenItemList.sort();
- bool encounteredPic = false;
- bool v81 = false;
+ bool pictureDrawn = false;
+ bool screenItemDrawn = false;
- for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- Common::Rect *rect = eraseList[i];
+ for (RectList::size_type i = 0; i < eraseListCount; ++i) {
+ const Common::Rect &rect = *eraseList[i];
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
ScreenItem *item = _screenItemList[j];
- if (j < _screenItemList.size() && item != nullptr) {
- if (rect->intersects(item->_screenRect)) {
- Common::Rect intersection = rect->findIntersectingRect(item->_screenRect);
- if (!item->_deleted) {
- if (encounteredPic) {
- if (item->_celInfo.type == kCelTypePic) {
- if (v81 || item->_celInfo.celNo == 0) {
- drawList.add(item, intersection);
- }
- } else {
- if (!item->_updated && !item->_created) {
- drawList.add(item, intersection);
- }
- v81 = true;
+ if (item == nullptr) {
+ continue;
+ }
+
+ if (rect.intersects(item->_screenRect)) {
+ const Common::Rect intersection = rect.findIntersectingRect(item->_screenRect);
+ if (!item->_deleted) {
+ if (pictureDrawn) {
+ if (item->_celInfo.type == kCelTypePic) {
+ if (screenItemDrawn || item->_celInfo.celNo == 0) {
+ mergeToDrawList(j, intersection, drawList);
}
} else {
if (!item->_updated && !item->_created) {
- drawList.add(item, intersection);
- }
- if (item->_celInfo.type == kCelTypePic) {
- encounteredPic = true;
+ mergeToDrawList(j, intersection, drawList);
}
+ screenItemDrawn = true;
+ }
+ } else {
+ if (!item->_updated && !item->_created) {
+ mergeToDrawList(j, intersection, drawList);
+ }
+ if (item->_celInfo.type == kCelTypePic) {
+ pictureDrawn = true;
}
}
}
@@ -423,35 +462,52 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
_screenItemList.unsort();
} else {
- // add all items overlapping the erase list to the draw list
- for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
+ // Add all items overlapping the erase list to the draw list
+ for (RectList::size_type i = 0; i < eraseListCount; ++i) {
+ const Common::Rect &rect = *eraseList[i];
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
ScreenItem *item = _screenItemList[j];
- if (j < _screenItemList.size() && item != nullptr && !item->_updated && !item->_deleted && !item->_created && eraseList[i]->intersects(item->_screenRect)) {
- drawList.add(item, eraseList[i]->findIntersectingRect(item->_screenRect));
+ if (
+ item != nullptr &&
+ !item->_created && !item->_updated && !item->_deleted &&
+ rect.intersects(item->_screenRect)
+ ) {
+ drawList.add(item, rect.findIntersectingRect(item->_screenRect));
}
}
}
}
- if (/* TODO: g_Remap_numActiveRemaps */ false) { // no remaps active?
+
+ if (g_sci->_gfxRemap32->getRemapCount() == 0) {
// Add all items that overlap with items in the drawlist and have higher
- // priority
- for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
- DrawItem *dli = drawList[i];
-
- for (PlaneList::size_type j = 0; j < planeItemCount; ++j) {
- ScreenItem *sli = _screenItemList[j];
-
- if (i < drawList.size() && dli) {
- if (j < _screenItemList.size() && sli) {
- if (!sli->_updated && !sli->_deleted && !sli->_created) {
- ScreenItem *item = dli->screenItem;
- if (sli->_priority > item->_priority || (sli->_priority == item->_priority && sli->_object > item->_object)) {
- if (dli->rect.intersects(sli->_screenRect)) {
- drawList.add(sli, dli->rect.findIntersectingRect(sli->_screenRect));
- }
- }
- }
+ // priority.
+
+ // We only loop over "primary" items in the draw list, skipping
+ // those that were added because of the erase list in the previous loop,
+ // or those to be added in this loop.
+ for (DrawList::size_type i = 0; i < drawListSizePrimary; ++i) {
+ const DrawItem *drawListEntry = nullptr;
+ if (i < drawList.size()) {
+ drawListEntry = drawList[i];
+ }
+
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ ScreenItem *newItem = nullptr;
+ if (j < _screenItemList.size()) {
+ newItem = _screenItemList[j];
+ }
+
+ if (
+ drawListEntry != nullptr && newItem != nullptr &&
+ !newItem->_created && !newItem->_updated && !newItem->_deleted
+ ) {
+ const ScreenItem *drawnItem = drawListEntry->screenItem;
+
+ if (
+ (newItem->_priority > drawnItem->_priority || (newItem->_priority == drawnItem->_priority && newItem->_object > drawnItem->_object)) &&
+ drawListEntry->rect.intersects(newItem->_screenRect)
+ ) {
+ mergeToDrawList(j, drawListEntry->rect.findIntersectingRect(newItem->_screenRect), drawList);
}
}
}
@@ -459,14 +515,11 @@ void Plane::calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList
}
decrementScreenItemArrayCounts(&visiblePlane, false);
- _screenItemList.pack();
- visiblePlane._screenItemList.pack();
}
void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate) {
- // The size of the screenItemList may change, so it is
- // critical to re-check the size on each iteration
- for (ScreenItemList::size_type i = 0; i < _screenItemList.size(); ++i) {
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
ScreenItem *item = _screenItemList[i];
if (item != nullptr) {
@@ -479,7 +532,7 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force
visiblePlane->_screenItemList.findByObject(item->_object) != nullptr
)
) {
- *visiblePlane->_screenItemList[i] = *_screenItemList[i];
+ *visiblePlane->_screenItemList[i] = *item;
}
if (item->_updated) {
@@ -490,8 +543,7 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force
if (item->_created) {
item->_created--;
if (visiblePlane != nullptr) {
- ScreenItem *n = new ScreenItem(*item);
- visiblePlane->_screenItemList.add(n);
+ visiblePlane->_screenItemList.add(new ScreenItem(*item));
}
}
@@ -499,177 +551,182 @@ void Plane::decrementScreenItemArrayCounts(Plane *visiblePlane, const bool force
if (item->_deleted) {
item->_deleted--;
if (!item->_deleted) {
- visiblePlane->_screenItemList.erase_at(i);
+ if (visiblePlane != nullptr && visiblePlane->_screenItemList.findByObject(item->_object) != nullptr) {
+ visiblePlane->_screenItemList.erase_at(i);
+ }
_screenItemList.erase_at(i);
}
}
}
}
+
+ _screenItemList.pack();
+ if (visiblePlane != nullptr) {
+ visiblePlane->_screenItemList.pack();
+ }
}
-void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const {
- if (_type == kPlaneTypeTransparent) {
- for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
- Common::Rect *r = transparentEraseList[i];
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
- if (item != nullptr) {
- if (r->intersects(item->_screenRect)) {
- mergeToDrawList(j, *r, drawList);
- }
+void Plane::filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) const {
+ const RectList::size_type higherEraseCount = higherEraseList.size();
+
+ if (_type == kPlaneTypeTransparent || _type == kPlaneTypeTransparentPicture) {
+ for (RectList::size_type i = 0; i < higherEraseCount; ++i) {
+ const Common::Rect &r = *higherEraseList[i];
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
}
} else {
- for (RectList::size_type i = 0; i < transparentEraseList.size(); ++i) {
- Common::Rect *r = transparentEraseList[i];
- if (r->intersects(_screenRect)) {
- r->clip(_screenRect);
- mergeToRectList(*r, eraseList);
-
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
-
- if (item != nullptr) {
- if (r->intersects(item->_screenRect)) {
- mergeToDrawList(j, *r, drawList);
- }
+ for (RectList::size_type i = 0; i < higherEraseCount; ++i) {
+ Common::Rect r = *higherEraseList[i];
+ if (r.intersects(_screenRect)) {
+ r.clip(_screenRect);
+ mergeToRectList(r, eraseList);
+
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
- Common::Rect ptr[4];
- Common::Rect *r2 = transparentEraseList[i];
- int count = splitRects(*r2, *r, ptr);
- for (int k = count - 1; k >= 0; --k) {
- transparentEraseList.add(ptr[k]);
+ Common::Rect outRects[4];
+ const Common::Rect &r2 = *higherEraseList[i];
+ int splitCount = splitRects(r2, r, outRects);
+ if (splitCount > 0) {
+ while (splitCount--) {
+ higherEraseList.add(outRects[splitCount]);
+ }
}
- transparentEraseList.erase_at(i);
+ higherEraseList.erase_at(i);
}
}
- transparentEraseList.pack();
+ higherEraseList.pack();
}
}
-void Plane::filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const {
- for (DrawList::size_type i = 0; i < drawList.size(); ++i) {
- Common::Rect &r = drawList[i]->rect;
-
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
- if (item != nullptr) {
- if (r.intersects(item->_screenRect)) {
- mergeToDrawList(j, r, transparentDrawList);
- }
+void Plane::filterUpDrawRects(DrawList &drawList, const DrawList &lowerDrawList) const {
+ const DrawList::size_type lowerDrawCount = lowerDrawList.size();
+ for (DrawList::size_type i = 0; i < lowerDrawCount; ++i) {
+ const Common::Rect &r = lowerDrawList[i]->rect;
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
}
}
-void Plane::filterUpEraseRects(DrawList &drawList, RectList &eraseList) const {
- for (RectList::size_type i = 0; i < eraseList.size(); ++i) {
- Common::Rect &r = *eraseList[i];
- for (ScreenItemList::size_type j = 0; j < _screenItemList.size(); ++j) {
- ScreenItem *item = _screenItemList[j];
-
- if (item != nullptr) {
- if (r.intersects(item->_screenRect)) {
- mergeToDrawList(j, r, drawList);
- }
+void Plane::filterUpEraseRects(DrawList &drawList, const RectList &lowerEraseList) const {
+ const RectList::size_type lowerEraseCount = lowerEraseList.size();
+ for (RectList::size_type i = 0; i < lowerEraseCount; ++i) {
+ const Common::Rect &r = *lowerEraseList[i];
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type j = 0; j < screenItemCount; ++j) {
+ const ScreenItem *item = _screenItemList[j];
+ if (item != nullptr && r.intersects(item->_screenRect)) {
+ mergeToDrawList(j, r, drawList);
}
}
}
}
-void Plane::mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const {
- RectList rects;
-
- Common::Rect r = _screenItemList[index]->_screenRect;
+void Plane::mergeToDrawList(const ScreenItemList::size_type index, const Common::Rect &rect, DrawList &drawList) const {
+ RectList mergeList;
+ ScreenItem &item = *_screenItemList[index];
+ Common::Rect r = item._screenRect;
r.clip(rect);
+ mergeList.add(r);
- rects.add(r);
- ScreenItem *item = _screenItemList[index];
-
- for (RectList::size_type i = 0; i < rects.size(); ++i) {
- r = *rects[i];
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ r = *mergeList[i];
- for (DrawList::size_type j = 0; j < drawList.size(); ++j) {
- DrawItem *drawitem = drawList[j];
- if (item->_object == drawitem->screenItem->_object) {
- if (drawitem->rect.contains(r)) {
- rects.erase_at(i);
+ const DrawList::size_type drawCount = drawList.size();
+ for (DrawList::size_type j = 0; j < drawCount; ++j) {
+ const DrawItem &drawItem = *drawList[j];
+ if (item._object == drawItem.screenItem->_object) {
+ if (drawItem.rect.contains(r)) {
+ mergeList.erase_at(i);
break;
}
Common::Rect outRects[4];
- int count = splitRects(r, drawitem->rect, outRects);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- rects.add(outRects[k]);
+ int splitCount = splitRects(r, drawItem.rect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
}
- rects.erase_at(i);
+ mergeList.erase_at(i);
// proceed to the next rect
- r = *rects[++i];
+ r = *mergeList[++i];
}
}
}
}
- rects.pack();
+ mergeList.pack();
- for (RectList::size_type i = 0; i < rects.size(); ++i) {
- drawList.add(item, *rects[i]);
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ drawList.add(&item, *mergeList[i]);
}
}
-void Plane::mergeToRectList(const Common::Rect &rect, RectList &rectList) const {
- RectList temp;
- temp.add(rect);
+void Plane::mergeToRectList(const Common::Rect &rect, RectList &eraseList) const {
+ RectList mergeList;
+ Common::Rect r;
+ mergeList.add(rect);
- for (RectList::size_type i = 0; i < temp.size(); ++i) {
- Common::Rect r = *temp[i];
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ r = *mergeList[i];
- for (RectList::size_type j = 0; j < rectList.size(); ++j) {
- Common::Rect *innerRect = rectList[j];
- if (innerRect->contains(r)) {
- temp.erase_at(i);
+ const RectList::size_type eraseCount = eraseList.size();
+ for (RectList::size_type j = 0; j < eraseCount; ++j) {
+ const Common::Rect &eraseRect = *eraseList[j];
+ if (eraseRect.contains(r)) {
+ mergeList.erase_at(i);
break;
}
- Common::Rect out[4];
- int count = splitRects(r, *innerRect, out);
- if (count != -1) {
- for (int k = count - 1; k >= 0; --k) {
- temp.add(out[k]);
+ Common::Rect outRects[4];
+ int splitCount = splitRects(r, eraseRect, outRects);
+ if (splitCount != -1) {
+ while (splitCount--) {
+ mergeList.add(outRects[splitCount]);
}
- temp.erase_at(i);
+ mergeList.erase_at(i);
// proceed to the next rect
- r = *temp[++i];
+ r = *mergeList[++i];
}
}
}
- temp.pack();
+ mergeList.pack();
- for (RectList::size_type i = 0; i < temp.size(); ++i) {
- rectList.add(*temp[i]);
+ for (RectList::size_type i = 0; i < mergeList.size(); ++i) {
+ eraseList.add(*mergeList[i]);
}
}
void Plane::redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList) {
- for (ScreenItemList::const_iterator screenItemPtr = _screenItemList.begin(); screenItemPtr != _screenItemList.end(); ++screenItemPtr) {
- if (*screenItemPtr != nullptr) {
- ScreenItem &screenItem = **screenItemPtr;
- if (!screenItem._deleted) {
- screenItem.getCelObj();
- screenItem.calcRects(*this);
- if (!screenItem._screenRect.isEmpty()) {
- drawList.add(&screenItem, screenItem._screenRect);
- }
+ const ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ ScreenItem *screenItem = _screenItemList[i];
+ if (screenItem != nullptr && !screenItem->_deleted) {
+ screenItem->calcRects(*this);
+ if (!screenItem->_screenRect.isEmpty()) {
+ mergeToDrawList(i, screenItem->_screenRect, drawList);
}
}
}
@@ -683,21 +740,27 @@ void Plane::redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList
breakDrawListByPlanes(drawList, planeList);
--_redrawAllCount;
decrementScreenItemArrayCounts(visiblePlane, true);
- _screenItemList.pack();
- if (visiblePlane != nullptr) {
- visiblePlane->_screenItemList.pack();
- }
}
void Plane::setType() {
- if (_pictureId == kPlanePicOpaque) {
- _type = kPlaneTypeOpaque;
- } else if (_pictureId == kPlanePicTransparent) {
- _type = kPlaneTypeTransparent;
- } else if (_pictureId == kPlanePicColored) {
+ switch (_pictureId) {
+ case kPlanePicColored:
_type = kPlaneTypeColored;
- } else {
- _type = kPlaneTypePicture;
+ break;
+ case kPlanePicTransparent:
+ _type = kPlaneTypeTransparent;
+ break;
+ case kPlanePicOpaque:
+ _type = kPlaneTypeOpaque;
+ break;
+ case kPlanePicTransparentPicture:
+ _type = kPlaneTypeTransparentPicture;
+ break;
+ default:
+ if (_type != kPlaneTypeTransparentPicture) {
+ _type = kPlaneTypePicture;
+ }
+ break;
}
}
@@ -718,10 +781,12 @@ void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
_planeRect.right > other->_planeRect.right ||
_planeRect.bottom > other->_planeRect.bottom
) {
+ // the plane moved or got larger
_redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
- _updated = g_sci->_gfxFrameout->getScreenCount();
+ _moved = g_sci->_gfxFrameout->getScreenCount();
} else if (_planeRect != other->_planeRect) {
- _updated = g_sci->_gfxFrameout->getScreenCount();
+ // the plane got smaller
+ _moved = g_sci->_gfxFrameout->getScreenCount();
}
if (_priority != other->_priority) {
@@ -742,12 +807,10 @@ void Plane::sync(const Plane *other, const Common::Rect &screenRect) {
_deleted = 0;
if (_created == 0) {
- _moved = g_sci->_gfxFrameout->getScreenCount();
+ _updated = g_sci->_gfxFrameout->getScreenCount();
}
convertGameRectToPlaneRect();
- _width = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- _height = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
_screenRect = _planeRect;
// NOTE: screenRect originally was retrieved through globals
// instead of being passed into the function
@@ -775,8 +838,48 @@ void Plane::update(const reg_t object) {
_back = readSelectorValue(segMan, object, SELECTOR(back));
}
+void Plane::scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool scrollPics) {
+ _redrawAllCount = g_sci->_gfxFrameout->getScreenCount();
+
+ for (ScreenItemList::iterator it = _screenItemList.begin(); it != _screenItemList.end(); ++it) {
+ if (*it != nullptr) {
+ ScreenItem &screenItem = **it;
+ if (!screenItem._deleted && (screenItem._celInfo.type != kCelTypePic || scrollPics)) {
+ screenItem._position.x += deltaX;
+ screenItem._position.y += deltaY;
+ }
+ }
+ }
+}
+
+void Plane::remapMarkRedraw() {
+ ScreenItemList::size_type screenItemCount = _screenItemList.size();
+ for (ScreenItemList::size_type i = 0; i < screenItemCount; ++i) {
+ ScreenItem *screenItem = _screenItemList[i];
+ if (
+ screenItem != nullptr &&
+ !screenItem->_deleted && !screenItem->_created &&
+ screenItem->getCelObj()._remap
+ ) {
+ screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+ }
+}
+
#pragma mark -
#pragma mark PlaneList
+
+void PlaneList::add(Plane *plane) {
+ for (iterator it = begin(); it != end(); ++it) {
+ if ((*it)->_priority > plane->_priority) {
+ insert(it, plane);
+ return;
+ }
+ }
+
+ push_back(plane);
+}
+
void PlaneList::clear() {
for (iterator it = begin(); it != end(); ++it) {
delete *it;
@@ -794,6 +897,11 @@ void PlaneList::erase(Plane *plane) {
}
}
+PlaneList::iterator PlaneList::erase(iterator it) {
+ delete *it;
+ return PlaneListBase::erase(it);
+}
+
int PlaneList::findIndexByObject(const reg_t object) const {
for (size_type i = 0; i < size(); ++i) {
if ((*this)[i] != nullptr && (*this)[i]->_object == object) {
@@ -836,15 +944,8 @@ int16 PlaneList::getTopSciPlanePriority() const {
return priority;
}
-void PlaneList::add(Plane *plane) {
- for (iterator it = begin(); it != end(); ++it) {
- if ((*it)->_priority < plane->_priority) {
- insert(it, plane);
- return;
- }
- }
-
- push_back(plane);
+void PlaneList::remove_at(size_type index) {
+ delete PlaneListBase::remove_at(index);
}
-}
+} // End of namespace Sci
diff --git a/engines/sci/graphics/plane32.h b/engines/sci/graphics/plane32.h
index be6f71464a..3981a2b319 100644
--- a/engines/sci/graphics/plane32.h
+++ b/engines/sci/graphics/plane32.h
@@ -32,19 +32,21 @@
namespace Sci {
enum PlaneType {
- kPlaneTypeColored = 0,
- kPlaneTypePicture = 1,
- kPlaneTypeTransparent = 2,
- kPlaneTypeOpaque = 3
+ kPlaneTypeColored = 0,
+ kPlaneTypePicture = 1,
+ kPlaneTypeTransparent = 2,
+ kPlaneTypeOpaque = 3,
+ kPlaneTypeTransparentPicture = 4
};
enum PlanePictureCodes {
- // NOTE: Any value at or below 65532 means the plane
+ // NOTE: Any value at or below 65531 means the plane
// is a kPlaneTypePicture.
- kPlanePic = 65532,
- kPlanePicOpaque = 65533,
- kPlanePicTransparent = 65534,
- kPlanePicColored = 65535
+ kPlanePic = 65531,
+ kPlanePicTransparentPicture = 65532,
+ kPlanePicOpaque = 65533,
+ kPlanePicTransparent = 65534,
+ kPlanePicColored = 65535
};
#pragma mark -
@@ -62,7 +64,14 @@ public:
#pragma mark DrawList
struct DrawItem {
+ /**
+ * The screen item to draw.
+ */
ScreenItem *screenItem;
+
+ /**
+ * The target rectangle of the draw operation.
+ */
Common::Rect rect;
inline bool operator<(const DrawItem &other) const {
@@ -101,16 +110,6 @@ private:
static uint16 _nextObjectId;
/**
- * The dimensions of the plane, in game script
- * coordinates.
- * TODO: These are never used and are always
- * scriptWidth x scriptHeight in SCI engine? The actual
- * dimensions of the plane are always in
- * gameRect/planeRect.
- */
- int16 _width, _height;
-
- /**
* For planes that are used to render picture data, the
* resource ID of the picture to be displayed. This
* value may also be one of the special
@@ -133,11 +132,7 @@ private:
* synchronised to another plane (which calls
* changePic).
*/
- bool _pictureChanged; // ?
-
- // TODO: Are these ever actually used?
- int _field_34, _field_38; // probably a point or ratio
- int _field_3C, _field_40; // probably a point or ratio
+ bool _pictureChanged;
/**
* Converts the dimensions of the game rect used by
@@ -155,6 +150,11 @@ private:
public:
/**
+ * The type of the plane.
+ */
+ PlaneType _type;
+
+ /**
* The color to use when erasing the plane. Only
* applies to planes of type kPlaneTypeColored.
*/
@@ -166,7 +166,7 @@ public:
* another plane and cleared when draw list calculation
* occurs.
*/
- int _priorityChanged; // ?
+ int _priorityChanged;
/**
* A handle to the VM object corresponding to this
@@ -182,12 +182,15 @@ public:
int16 _priority;
/**
- * TODO: Document
+ * Whether or not all screen items in this plane should
+ * be redrawn on the next frameout, instead of just
+ * the screen items marked as updated. This is set when
+ * visual changes to the plane itself are made that
+ * affect the rendering of the entire plane, and cleared
+ * once those changes are rendered by `redrawAll`.
*/
int _redrawAllCount;
- PlaneType _type;
-
/**
* Flags indicating the state of the plane.
* - `created` is set when the plane is first created,
@@ -198,16 +201,15 @@ public:
* not match
* - `deleted` is set when the plane is deleted by a
* kernel call
- * - `moved` is set when the plane is synchronised from
- * another plane and is not already in the "created"
- * state
+ * - `moved` is set when the plane has been moved or
+ * resized
*/
int _created, _updated, _deleted, _moved;
/**
* The vanishing point for the plane. Used when
- * calculating the correct scaling of the plane's screen
- * items according to their position.
+ * automatically calculating the correct scaling of the
+ * plane's screen items according to their position.
*/
Common::Point _vanishingPoint;
@@ -241,30 +243,28 @@ public:
*/
static void init();
- Plane(const Common::Rect &gameRect);
+ // NOTE: This constructor signature originally did not accept a
+ // picture ID, but some calls to construct planes with this signature
+ // immediately set the picture ID and then called setType again, so
+ // it made more sense to just make the picture ID a parameter instead.
+ Plane(const Common::Rect &gameRect, PlanePictureCodes pictureId = kPlanePicColored);
+
Plane(const reg_t object);
+
Plane(const Plane &other);
+
void operator=(const Plane &other);
+
inline bool operator<(const Plane &other) const {
- // TODO: In SCI engine, _object is actually a uint16 and can either
- // contain a MemID (a handle to MemoryMgr, similar to reg_t) or
- // a serial (Plane::_nextObjectId). These numbers can be compared
- // directly in the real engine and the lowest MemID wins, but in
- // ScummVM reg_t pointers are not comparable so we have to use a
- // different strategy when two planes generated by scripts conflict.
- // For now we just don't check if the priority is below 0, since
- // that priority is used to represent hidden planes and is guaranteed
- // to generate conflicts with script-generated planes. If there are
- // other future conflicts with script-generated planes then we need
- // to come up with a solution that works, similar to
- // reg_t::pointerComparisonWithInteger used by SCI16.
- //
- // For now, we check the object offsets, as this will likely work
- // like in the original SCI engine, without comparing objects.
- // However, this whole comparison is quite ugly, and if it still
- // fails, we should try to change it to something equivalent, to avoid
- // adding loads of workarounds just for this
- return _priority < other._priority || (_priority == other._priority && _priority > -1 && _object.getOffset() < other._object.getOffset());
+ if (_priority < other._priority) {
+ return true;
+ }
+
+ if (_priority == other._priority) {
+ return _object < other._object;
+ }
+
+ return false;
}
/**
@@ -272,7 +272,11 @@ public:
* given screen rect.
*/
inline void clipScreenRect(const Common::Rect &screenRect) {
- if (_screenRect.intersects(screenRect)) {
+ // LSL6 hires creates planes with invalid rects; SSCI does not
+ // care about this, but `Common::Rect::clip` does, so we need to
+ // check whether or not the rect is actually valid before clipping
+ // and only clip valid rects
+ if (_screenRect.isValidRect() && _screenRect.intersects(screenRect)) {
_screenRect.clip(screenRect);
} else {
_screenRect.left = 0;
@@ -305,6 +309,13 @@ public:
*/
void update(const reg_t object);
+ /**
+ * Modifies the position of all non-pic screen items
+ * by the given delta. If `scrollPics` is true, pic
+ * items are also repositioned.
+ */
+ void scrollScreenItems(const int16 deltaX, const int16 deltaY, const bool scrollPics);
+
#pragma mark -
#pragma mark Plane - Pic
private:
@@ -318,12 +329,6 @@ private:
inline void addPicInternal(const GuiResourceId pictureId, const Common::Point *position, const bool mirrorX);
/**
- * If the plane is a picture plane, re-adds all cels
- * from its picture resource to the plane.
- */
- void changePic();
-
- /**
* Marks all screen items to be deleted that are within
* this plane and match the given picture ID.
*/
@@ -352,47 +357,45 @@ public:
*/
void addPic(const GuiResourceId pictureId, const Common::Point &position, const bool mirrorX);
+ /**
+ * If the plane is a picture plane, re-adds all cels
+ * from its picture resource to the plane. Otherwise,
+ * just clears the _pictureChanged flag.
+ */
+ void changePic();
+
#pragma mark -
#pragma mark Plane - Rendering
private:
/**
* Splits all rects in the given draw list at the edges
- * of all non-transparent planes above the current
- * plane.
+ * of all higher-priority, non-transparent, intersecting
+ * planes.
*/
void breakDrawListByPlanes(DrawList &drawList, const PlaneList &planeList) const;
/**
- * Splits all rects in the given erase list rects at the
- * edges of all non-transparent planes above the current
- * plane.
+ * Splits all rects in the given erase list at the
+ * edges of higher-priority, non-transparent,
+ * intersecting planes.
*/
void breakEraseListByPlanes(RectList &eraseList, const PlaneList &planeList) const;
/**
- * Synchronises changes to screen items from the current
- * plane to the visible plane and deletes screen items
- * from the current plane that have been marked as
- * deleted. If `forceUpdate` is true, all screen items
- * on the visible plane will be updated, even if they
- * are not marked as having changed.
- */
- void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate);
-
- /**
- * Merges the screen item from this plane at the given
- * index into the given draw list, clipped to the given
- * rect. TODO: Finish documenting
+ * Adds the screen item at `index` into `drawList`,
+ * ensuring it is only drawn within the bounds of
+ * `rect`. If an existing draw list entry exists
+ * for this screen item, it will be modified.
+ * Otherwise, a new entry will be added.
*/
void mergeToDrawList(const DrawList::size_type index, const Common::Rect &rect, DrawList &drawList) const;
/**
- * Adds the given rect into the given rect list,
- * merging it with other rects already inside the list,
- * if possible, to avoid overdraw. TODO: Finish
- * documenting
+ * Merges `rect` with an existing rect in `eraseList`,
+ * if possible. Otherwise, adds the rect as a new entry
+ * to `eraseList`.
*/
- void mergeToRectList(const Common::Rect &rect, RectList &rectList) const;
+ void mergeToRectList(const Common::Rect &rect, RectList &eraseList) const;
public:
/**
@@ -405,25 +408,81 @@ public:
void calcLists(Plane &visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
/**
- * TODO: Documentation
+ * Synchronises changes to screen items from the current
+ * plane to the visible plane and deletes screen items
+ * from the current plane that have been marked as
+ * deleted. If `forceUpdate` is true, all screen items
+ * on the visible plane will be updated, even if they
+ * are not marked as having changed.
*/
- void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &transparentEraseList) const;
+ void decrementScreenItemArrayCounts(Plane *visiblePlane, const bool forceUpdate);
/**
- * TODO: Documentation
+ * This method is called from the highest priority plane
+ * to the lowest priority plane.
+ *
+ * Adds screen items from this plane to the draw list
+ * that must be redrawn because they intersect entries
+ * in the `higherEraseList`.
+ *
+ * If this plane is opaque, all intersecting erase rects
+ * in `lowerEraseList` are removed, as they would be
+ * completely overwritten by the contents of this plane.
+ *
+ * If this plane is transparent, erase rects from the
+ * `lowerEraseList` are added to the erase list for this
+ * plane, so that lower planes.
+ *
+ * @param drawList The draw list for this plane.
+ * @param eraseList The erase list for this plane.
+ * @param higherEraseList The erase list for a plane
+ * above this plane.
*/
- void filterUpEraseRects(DrawList &drawList, RectList &eraseList) const;
+ void filterDownEraseRects(DrawList &drawList, RectList &eraseList, RectList &higherEraseList) const;
/**
- * TODO: Documentation
+ * This method is called from the lowest priority plane
+ * to the highest priority plane.
+ *
+ * Adds screen items from this plane to the draw list
+ * that must be drawn because the lower plane is being
+ * redrawn and potentially transparent screen items
+ * from this plane would draw over the lower priority
+ * plane's screen items.
+ *
+ * This method applies only to transparent planes.
+ *
+ * @param drawList The draw list for this plane.
+ * @param eraseList The erase list for a plane below
+ * this plane.
+ */
+ void filterUpEraseRects(DrawList &drawList, const RectList &lowerEraseList) const;
+
+ /**
+ * This method is called from the lowest priority plane
+ * to the highest priority plane.
+ *
+ * Adds screen items from this plane to the draw list
+ * that must be drawn because the lower plane is being
+ * redrawn and potentially transparent screen items
+ * from this plane would draw over the lower priority
+ * plane's screen items.
+ *
+ * This method applies only to transparent planes.
+ *
+ * @param drawList The draw list for this plane.
+ * @param lowerDrawList The draw list for a plane below
+ * this plane.
*/
- void filterUpDrawRects(DrawList &transparentDrawList, const DrawList &drawList) const;
+ void filterUpDrawRects(DrawList &drawList, const DrawList &lowerDrawList) const;
/**
* Updates all of the plane's non-deleted screen items
* and adds them to the given draw and erase lists.
*/
void redrawAll(Plane *visiblePlane, const PlaneList &planeList, DrawList &drawList, RectList &eraseList);
+
+ void remapMarkRedraw();
};
#pragma mark -
@@ -459,13 +518,14 @@ public:
void add(Plane *plane);
void clear();
- using PlaneListBase::erase;
+ iterator erase(iterator it);
void erase(Plane *plane);
inline void sort() {
Common::sort(begin(), end(), sortHelper);
}
+ void remove_at(size_type index);
};
-}
+} // End of namespace Sci
#endif
diff --git a/engines/sci/graphics/remap.cpp b/engines/sci/graphics/remap.cpp
new file mode 100644
index 0000000000..2abf03ea29
--- /dev/null
+++ b/engines/sci/graphics/remap.cpp
@@ -0,0 +1,99 @@
+/* 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.
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/graphics/palette.h"
+#include "sci/graphics/remap.h"
+#include "sci/graphics/screen.h"
+
+namespace Sci {
+
+GfxRemap::GfxRemap(GfxPalette *palette)
+ : _palette(palette) {
+ _remapOn = false;
+ resetRemapping();
+}
+
+byte GfxRemap::remapColor(byte remappedColor, byte screenColor) {
+ assert(_remapOn);
+ if (_remappingType[remappedColor] == kRemapByRange)
+ return _remappingByRange[screenColor];
+ else if (_remappingType[remappedColor] == kRemapByPercent)
+ return _remappingByPercent[screenColor];
+ else
+ error("remapColor(): Color %d isn't remapped", remappedColor);
+
+ return 0; // should never reach here
+}
+
+void GfxRemap::resetRemapping() {
+ _remapOn = false;
+ _remappingPercentToSet = 0;
+
+ for (int i = 0; i < 256; i++) {
+ _remappingType[i] = kRemapNone;
+ _remappingByPercent[i] = i;
+ _remappingByRange[i] = i;
+ }
+}
+
+void GfxRemap::setRemappingPercent(byte color, byte percent) {
+ _remapOn = true;
+
+ // We need to defer the setup of the remapping table every time the screen
+ // palette is changed, so that kernelFindColor() can find the correct
+ // colors. Set it once here, in case the palette stays the same and update
+ // it on each palette change by copySysPaletteToScreen().
+ _remappingPercentToSet = percent;
+
+ for (int i = 0; i < 256; i++) {
+ byte r = _palette->_sysPalette.colors[i].r * _remappingPercentToSet / 100;
+ byte g = _palette->_sysPalette.colors[i].g * _remappingPercentToSet / 100;
+ byte b = _palette->_sysPalette.colors[i].b * _remappingPercentToSet / 100;
+ _remappingByPercent[i] = _palette->kernelFindColor(r, g, b);
+ }
+
+ _remappingType[color] = kRemapByPercent;
+}
+
+void GfxRemap::setRemappingRange(byte color, byte from, byte to, byte base) {
+ _remapOn = true;
+
+ for (int i = from; i <= to; i++) {
+ _remappingByRange[i] = i + base;
+ }
+
+ _remappingType[color] = kRemapByRange;
+}
+
+void GfxRemap::updateRemapping() {
+ // Check if we need to reset remapping by percent with the new colors.
+ if (_remappingPercentToSet) {
+ for (int i = 0; i < 256; i++) {
+ byte r = _palette->_sysPalette.colors[i].r * _remappingPercentToSet / 100;
+ byte g = _palette->_sysPalette.colors[i].g * _remappingPercentToSet / 100;
+ byte b = _palette->_sysPalette.colors[i].b * _remappingPercentToSet / 100;
+ _remappingByPercent[i] = _palette->kernelFindColor(r, g, b);
+ }
+ }
+}
+} // End of namespace Sci
diff --git a/engines/sci/graphics/remap.h b/engines/sci/graphics/remap.h
new file mode 100644
index 0000000000..98177f6d19
--- /dev/null
+++ b/engines/sci/graphics/remap.h
@@ -0,0 +1,67 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_REMAP_H
+#define SCI_GRAPHICS_REMAP_H
+
+#include "common/array.h"
+#include "common/serializer.h"
+
+namespace Sci {
+
+class GfxScreen;
+
+/**
+ * This class handles color remapping for the QFG4 demo.
+ */
+class GfxRemap {
+private:
+ enum ColorRemappingType {
+ kRemapNone = 0,
+ kRemapByRange = 1,
+ kRemapByPercent = 2
+ };
+
+public:
+ GfxRemap(GfxPalette *_palette);
+
+ void resetRemapping();
+ void setRemappingPercent(byte color, byte percent);
+ void setRemappingRange(byte color, byte from, byte to, byte base);
+ bool isRemapped(byte color) const {
+ return _remapOn && (_remappingType[color] != kRemapNone);
+ }
+ byte remapColor(byte remappedColor, byte screenColor);
+ void updateRemapping();
+
+private:
+ GfxPalette *_palette;
+
+ bool _remapOn;
+ ColorRemappingType _remappingType[256];
+ byte _remappingByPercent[256];
+ byte _remappingByRange[256];
+ uint16 _remappingPercentToSet;
+};
+} // End of namespace Sci
+
+#endif
diff --git a/engines/sci/graphics/remap32.cpp b/engines/sci/graphics/remap32.cpp
new file mode 100644
index 0000000000..d5a2362f14
--- /dev/null
+++ b/engines/sci/graphics/remap32.cpp
@@ -0,0 +1,468 @@
+/* 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.
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
+
+namespace Sci {
+
+#pragma mark SingleRemap
+
+void SingleRemap::reset() {
+ _lastPercent = 100;
+ _lastGray = 0;
+
+ const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
+ const Palette &currentPalette = g_sci->_gfxPalette32->getCurrentPalette();
+ for (uint i = 0; i < remapStartColor; ++i) {
+ const Color &color = currentPalette.colors[i];
+ _remapColors[i] = i;
+ _originalColors[i] = color;
+ _originalColorsChanged[i] = true;
+ _idealColors[i] = color;
+ _idealColorsChanged[i] = false;
+ _matchDistances[i] = 0;
+ }
+}
+
+bool SingleRemap::update() {
+ switch (_type) {
+ case kRemapNone:
+ break;
+ case kRemapByRange:
+ return updateRange();
+ case kRemapByPercent:
+ return updateBrightness();
+ case kRemapToGray:
+ return updateSaturation();
+ case kRemapToPercentGray:
+ return updateSaturationAndBrightness();
+ default:
+ error("Illegal remap type %d", _type);
+ }
+
+ return false;
+}
+
+bool SingleRemap::updateRange() {
+ const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
+ bool updated = false;
+
+ for (uint i = 0; i < remapStartColor; ++i) {
+ uint8 targetColor;
+ if (_from <= i && i <= _to) {
+ targetColor = i + _delta;
+ } else {
+ targetColor = i;
+ }
+
+ if (_remapColors[i] != targetColor) {
+ updated = true;
+ _remapColors[i] = targetColor;
+ }
+
+ _originalColorsChanged[i] = true;
+ }
+
+ return updated;
+}
+
+bool SingleRemap::updateBrightness() {
+ const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
+ const Palette &nextPalette = g_sci->_gfxPalette32->getNextPalette();
+ for (uint i = 1; i < remapStartColor; ++i) {
+ Color color(nextPalette.colors[i]);
+
+ if (_originalColors[i] != color) {
+ _originalColorsChanged[i] = true;
+ _originalColors[i] = color;
+ }
+
+ if (_percent != _lastPercent || _originalColorsChanged[i]) {
+ // NOTE: SSCI checked if percent was over 100 and only
+ // then clipped values, but we always unconditionally
+ // ensure the result is in the correct range
+ color.r = MIN(255, (uint16)color.r * _percent / 100);
+ color.g = MIN(255, (uint16)color.g * _percent / 100);
+ color.b = MIN(255, (uint16)color.b * _percent / 100);
+
+ if (_idealColors[i] != color) {
+ _idealColorsChanged[i] = true;
+ _idealColors[i] = color;
+ }
+ }
+ }
+
+ const bool updated = apply();
+ Common::fill(_originalColorsChanged, _originalColorsChanged + remapStartColor, false);
+ Common::fill(_idealColorsChanged, _idealColorsChanged + remapStartColor, false);
+ _lastPercent = _percent;
+ return updated;
+}
+
+bool SingleRemap::updateSaturation() {
+ const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
+ const Palette &currentPalette = g_sci->_gfxPalette32->getCurrentPalette();
+ for (uint i = 1; i < remapStartColor; ++i) {
+ Color color(currentPalette.colors[i]);
+ if (_originalColors[i] != color) {
+ _originalColorsChanged[i] = true;
+ _originalColors[i] = color;
+ }
+
+ if (_gray != _lastGray || _originalColorsChanged[i]) {
+ const int luminosity = (((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8) * _percent / 100;
+
+ color.r = MIN(255, color.r - ((color.r - luminosity) * _gray / 100));
+ color.g = MIN(255, color.g - ((color.g - luminosity) * _gray / 100));
+ color.b = MIN(255, color.b - ((color.b - luminosity) * _gray / 100));
+
+ if (_idealColors[i] != color) {
+ _idealColorsChanged[i] = true;
+ _idealColors[i] = color;
+ }
+ }
+ }
+
+ const bool updated = apply();
+ Common::fill(_originalColorsChanged, _originalColorsChanged + remapStartColor, false);
+ Common::fill(_idealColorsChanged, _idealColorsChanged + remapStartColor, false);
+ _lastGray = _gray;
+ return updated;
+}
+
+bool SingleRemap::updateSaturationAndBrightness() {
+ const uint8 remapStartColor = g_sci->_gfxRemap32->getStartColor();
+ const Palette &currentPalette = g_sci->_gfxPalette32->getCurrentPalette();
+ for (uint i = 1; i < remapStartColor; i++) {
+ Color color(currentPalette.colors[i]);
+ if (_originalColors[i] != color) {
+ _originalColorsChanged[i] = true;
+ _originalColors[i] = color;
+ }
+
+ if (_percent != _lastPercent || _gray != _lastGray || _originalColorsChanged[i]) {
+ const int luminosity = (((color.r * 77) + (color.g * 151) + (color.b * 28)) >> 8) * _percent / 100;
+
+ color.r = MIN(255, color.r - ((color.r - luminosity) * _gray) / 100);
+ color.g = MIN(255, color.g - ((color.g - luminosity) * _gray) / 100);
+ color.b = MIN(255, color.b - ((color.b - luminosity) * _gray) / 100);
+
+ if (_idealColors[i] != color) {
+ _idealColorsChanged[i] = true;
+ _idealColors[i] = color;
+ }
+ }
+ }
+
+ const bool updated = apply();
+ Common::fill(_originalColorsChanged, _originalColorsChanged + remapStartColor, false);
+ Common::fill(_idealColorsChanged, _idealColorsChanged + remapStartColor, false);
+ _lastPercent = _percent;
+ _lastGray = _gray;
+ return updated;
+}
+
+bool SingleRemap::apply() {
+ const GfxRemap32 *const gfxRemap32 = g_sci->_gfxRemap32;
+ const uint8 remapStartColor = gfxRemap32->getStartColor();
+
+ // Blocked colors are not allowed to be used as target
+ // colors for the remap
+ bool blockedColors[236];
+ Common::fill(blockedColors, blockedColors + remapStartColor, false);
+
+ const bool *const paletteCycleMap = g_sci->_gfxPalette32->getCycleMap();
+
+ const int16 blockedRangeCount = gfxRemap32->getBlockedRangeCount();
+ if (blockedRangeCount) {
+ const uint8 blockedRangeStart = gfxRemap32->getBlockedRangeStart();
+ Common::fill(blockedColors + blockedRangeStart, blockedColors + blockedRangeStart + blockedRangeCount, true);
+ }
+
+ for (uint i = 0; i < remapStartColor; ++i) {
+ if (paletteCycleMap[i]) {
+ blockedColors[i] = true;
+ }
+ }
+
+ // NOTE: SSCI did a loop over colors here to create a
+ // new array of updated, unblocked colors, but then
+ // never used it
+
+ bool updated = false;
+ for (uint i = 1; i < remapStartColor; ++i) {
+ int distance;
+
+ if (!_idealColorsChanged[i] && !_originalColorsChanged[_remapColors[i]]) {
+ continue;
+ }
+
+ if (
+ _idealColorsChanged[i] &&
+ _originalColorsChanged[_remapColors[i]] &&
+ _matchDistances[i] < 100 &&
+ colorDistance(_idealColors[i], _originalColors[_remapColors[i]]) <= _matchDistances[i]
+ ) {
+ continue;
+ }
+
+ const int16 bestColor = matchColor(_idealColors[i], _matchDistances[i], distance, blockedColors);
+
+ if (bestColor != -1 && _remapColors[i] != bestColor) {
+ updated = true;
+ _remapColors[i] = bestColor;
+ _matchDistances[i] = distance;
+ }
+ }
+
+ return updated;
+}
+
+int SingleRemap::colorDistance(const Color &a, const Color &b) const {
+ int channelDistance = a.r - b.r;
+ int distance = channelDistance * channelDistance;
+ channelDistance = a.g - b.g;
+ distance += channelDistance * channelDistance;
+ channelDistance = a.b - b.b;
+ distance += channelDistance * channelDistance;
+ return distance;
+}
+
+int16 SingleRemap::matchColor(const Color &color, const int minimumDistance, int &outDistance, const bool *const blockedIndexes) const {
+ int16 bestIndex = -1;
+ int bestDistance = 0xFFFFF;
+ int distance = minimumDistance;
+ const Palette &nextPalette = g_sci->_gfxPalette32->getNextPalette();
+
+ for (uint i = 0, channelDistance; i < g_sci->_gfxRemap32->getStartColor(); ++i) {
+ if (blockedIndexes[i]) {
+ continue;
+ }
+
+ distance = nextPalette.colors[i].r - color.r;
+ distance *= distance;
+ if (bestDistance <= distance) {
+ continue;
+ }
+ channelDistance = nextPalette.colors[i].g - color.g;
+ distance += channelDistance * channelDistance;
+ if (bestDistance <= distance) {
+ continue;
+ }
+ channelDistance = nextPalette.colors[i].b - color.b;
+ distance += channelDistance * channelDistance;
+ if (bestDistance <= distance) {
+ continue;
+ }
+ bestDistance = distance;
+ bestIndex = i;
+ }
+
+ // This value is only valid if the last index to
+ // perform a distance calculation was the best index
+ outDistance = distance;
+ return bestIndex;
+}
+
+#pragma mark -
+#pragma mark GfxRemap32
+
+GfxRemap32::GfxRemap32() :
+ _needsUpdate(false),
+ _blockedRangeStart(0),
+ _blockedRangeCount(0),
+ _remapStartColor(236),
+ _numActiveRemaps(0) {
+ // The `_remapStartColor` seems to always be 236 in SSCI,
+ // but if it is ever changed then the various C-style
+ // member arrays hard-coded to 236 need to be changed to
+ // match the highest possible value of `_remapStartColor`
+ assert(_remapStartColor == 236);
+
+ if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE || g_sci->getGameId() == GID_KQ7) {
+ _remaps.resize(9);
+ } else {
+ _remaps.resize(19);
+ }
+
+ _remapEndColor = _remapStartColor + _remaps.size() - 1;
+}
+
+void GfxRemap32::remapOff(const uint8 color) {
+ if (color == 0) {
+ remapAllOff();
+ return;
+ }
+
+ // NOTE: SSCI simply ignored invalid input values, but
+ // we at least give a warning so games can be investigated
+ // for script bugs
+ if (color < _remapStartColor || color > _remapEndColor) {
+ warning("GfxRemap32::remapOff: %d out of remap range", color);
+ return;
+ }
+
+ const uint8 index = _remapEndColor - color;
+ SingleRemap &singleRemap = _remaps[index];
+ singleRemap._type = kRemapNone;
+ --_numActiveRemaps;
+ _needsUpdate = true;
+}
+
+void GfxRemap32::remapAllOff() {
+ for (uint i = 0, len = _remaps.size(); i < len; ++i) {
+ _remaps[i]._type = kRemapNone;
+ }
+
+ _numActiveRemaps = 0;
+ _needsUpdate = true;
+}
+
+void GfxRemap32::remapByRange(const uint8 color, const int16 from, const int16 to, const int16 delta) {
+ // NOTE: SSCI simply ignored invalid input values, but
+ // we at least give a warning so games can be investigated
+ // for script bugs
+ if (color < _remapStartColor || color > _remapEndColor) {
+ warning("GfxRemap32::remapByRange: %d out of remap range", color);
+ return;
+ }
+
+ if (from < 0) {
+ warning("GfxRemap32::remapByRange: attempt to remap negative color %d", from);
+ return;
+ }
+
+ if (to >= _remapStartColor) {
+ warning("GfxRemap32::remapByRange: attempt to remap into the remap zone at %d", to);
+ return;
+ }
+
+ const uint8 index = _remapEndColor - color;
+ SingleRemap &singleRemap = _remaps[index];
+
+ if (singleRemap._type == kRemapNone) {
+ ++_numActiveRemaps;
+ singleRemap.reset();
+ }
+
+ singleRemap._from = from;
+ singleRemap._to = to;
+ singleRemap._delta = delta;
+ singleRemap._type = kRemapByRange;
+ _needsUpdate = true;
+}
+
+void GfxRemap32::remapByPercent(const uint8 color, const int16 percent) {
+ // NOTE: SSCI simply ignored invalid input values, but
+ // we at least give a warning so games can be investigated
+ // for script bugs
+ if (color < _remapStartColor || color > _remapEndColor) {
+ warning("GfxRemap32::remapByPercent: %d out of remap range", color);
+ return;
+ }
+
+ const uint8 index = _remapEndColor - color;
+ SingleRemap &singleRemap = _remaps[index];
+
+ if (singleRemap._type == kRemapNone) {
+ ++_numActiveRemaps;
+ singleRemap.reset();
+ }
+
+ singleRemap._percent = percent;
+ singleRemap._type = kRemapByPercent;
+ _needsUpdate = true;
+}
+
+void GfxRemap32::remapToGray(const uint8 color, const int8 gray) {
+ // NOTE: SSCI simply ignored invalid input values, but
+ // we at least give a warning so games can be investigated
+ // for script bugs
+ if (color < _remapStartColor || color > _remapEndColor) {
+ warning("GfxRemap32::remapToGray: %d out of remap range", color);
+ return;
+ }
+
+ if (gray < 0 || gray > 100) {
+ error("RemapToGray percent out of range; gray = %d", gray);
+ }
+
+ const uint8 index = _remapEndColor - color;
+ SingleRemap &singleRemap = _remaps[index];
+
+ if (singleRemap._type == kRemapNone) {
+ ++_numActiveRemaps;
+ singleRemap.reset();
+ }
+
+ singleRemap._gray = gray;
+ singleRemap._type = kRemapToGray;
+ _needsUpdate = true;
+}
+
+void GfxRemap32::remapToPercentGray(const uint8 color, const int16 gray, const int16 percent) {
+ // NOTE: SSCI simply ignored invalid input values, but
+ // we at least give a warning so games can be investigated
+ // for script bugs
+ if (color < _remapStartColor || color > _remapEndColor) {
+ warning("GfxRemap32::remapToPercentGray: %d out of remap range", color);
+ return;
+ }
+
+ const uint8 index = _remapEndColor - color;
+ SingleRemap &singleRemap = _remaps[index];
+
+ if (singleRemap._type == kRemapNone) {
+ ++_numActiveRemaps;
+ singleRemap.reset();
+ }
+
+ singleRemap._percent = percent;
+ singleRemap._gray = gray;
+ singleRemap._type = kRemapToPercentGray;
+ _needsUpdate = true;
+}
+
+void GfxRemap32::blockRange(const uint8 from, const int16 count) {
+ _blockedRangeStart = from;
+ _blockedRangeCount = count;
+}
+
+bool GfxRemap32::remapAllTables(const bool paletteUpdated) {
+ if (!_needsUpdate && !paletteUpdated) {
+ return false;
+ }
+
+ bool updated = false;
+
+ for (SingleRemapsList::iterator it = _remaps.begin(); it != _remaps.end(); ++it) {
+ if (it->_type != kRemapNone) {
+ updated |= it->update();
+ }
+ }
+
+ _needsUpdate = false;
+ return updated;
+}
+} // End of namespace Sci
diff --git a/engines/sci/graphics/remap32.h b/engines/sci/graphics/remap32.h
new file mode 100644
index 0000000000..5f629d733e
--- /dev/null
+++ b/engines/sci/graphics/remap32.h
@@ -0,0 +1,400 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_REMAP32_H
+#define SCI_GRAPHICS_REMAP32_H
+
+#include "common/algorithm.h"
+#include "common/array.h"
+#include "common/scummsys.h"
+#include "sci/graphics/helpers.h"
+
+namespace Sci {
+class GfxPalette32;
+
+enum RemapType {
+ kRemapNone = 0,
+ kRemapByRange = 1,
+ kRemapByPercent = 2,
+ kRemapToGray = 3,
+ kRemapToPercentGray = 4
+};
+
+#pragma mark -
+#pragma mark SingleRemap
+
+/**
+ * SingleRemap objects each manage one remapping operation.
+ */
+class SingleRemap {
+public:
+ SingleRemap() : _type(kRemapNone) {}
+
+ /**
+ * The type of remap.
+ */
+ RemapType _type;
+
+ /**
+ * The first color that should be shifted by a range
+ * remap.
+ */
+ uint8 _from;
+
+ /**
+ * The last color that should be shifted a range remap.
+ */
+ uint8 _to;
+
+ /**
+ * The direction and amount that the colors should be
+ * shifted in a range remap.
+ */
+ int16 _delta;
+
+ /**
+ * The difference in brightness that should be
+ * applied by a brightness (percent) remap.
+ *
+ * This value may be be greater than 100, in
+ * which case the color will be oversaturated.
+ */
+ int16 _percent;
+
+ /**
+ * The amount of desaturation that should be
+ * applied by a saturation (gray) remap, where
+ * 0 is full saturation and 100 is full
+ * desaturation.
+ */
+ uint8 _gray;
+
+ /**
+ * The final array used by CelObj renderers to composite
+ * remapped pixels to the screen buffer.
+ *
+ * Here is how it works:
+ *
+ * The source bitmap being rendered will have pixels
+ * within the remap range (236-245 or 236-254), and the
+ * target buffer will have colors in the non-remapped
+ * range (0-235).
+ *
+ * To arrive at the correct color, first the source
+ * pixel is used to look up the correct SingleRemap for
+ * that pixel. Then, the final composited color is
+ * looked up in this array using the target's pixel
+ * color. In other words,
+ * `target = _remaps[remapEndColor - source].remapColors[target]`.
+ */
+ uint8 _remapColors[236];
+
+ /**
+ * Resets this SingleRemap's color information to
+ * default values.
+ */
+ void reset();
+
+ /**
+ * Recalculates and reapplies remap colors to the
+ * `_remapColors` array.
+ */
+ bool update();
+
+private:
+ /**
+ * The previous brightness value. Used to
+ * determine whether or not targetColors needs
+ * to be updated.
+ */
+ int16 _lastPercent;
+
+ /**
+ * The previous saturation value. Used to
+ * determine whether or not targetColors needs
+ * to be updated.
+ */
+ uint8 _lastGray;
+
+ /**
+ * The colors from the current GfxPalette32 palette
+ * before this SingleRemap is applied.
+ */
+ Color _originalColors[236];
+
+ /**
+ * Map of colors that changed in `_originalColors`
+ * when this SingleRemap was updated. This map is
+ * transient and gets reset to `false` after the
+ * SingleRemap finishes updating.
+ */
+ bool _originalColorsChanged[236];
+
+ /**
+ * The ideal target RGB color values for each generated
+ * remap color.
+ */
+ Color _idealColors[236];
+
+ /**
+ * Map of colors that changed in `_idealColors` when
+ * this SingleRemap was updated. This map is transient
+ * and gets reset to `false` after the SingleRemap
+ * finishes applying.
+ */
+ bool _idealColorsChanged[236];
+
+ /**
+ * When applying a SingleRemap, finding an appropriate
+ * color in the palette is the responsibility of a
+ * distance function. Once a match is found, the
+ * distance of that match is stored here so that the
+ * next time the SingleRemap is applied, it can check
+ * the distance from the previous application and avoid
+ * triggering an expensive redraw of the entire screen
+ * if the new palette value only changed slightly.
+ */
+ int _matchDistances[236];
+
+ /**
+ * Computes the final target values for a range remap
+ * and applies them directly to the `_remaps` map.
+ *
+ * @note Was ByRange in SSCI.
+ */
+ bool updateRange();
+
+ /**
+ * Computes the intermediate target values for a
+ * brightness remap and applies them indirectly via
+ * the `apply` method.
+ *
+ * @note Was ByPercent in SSCI.
+ */
+ bool updateBrightness();
+
+ /**
+ * Computes the intermediate target values for a
+ * saturation remap and applies them indirectly via
+ * the `apply` method.
+ *
+ * @note Was ToGray in SSCI.
+ */
+ bool updateSaturation();
+
+ /**
+ * Computes the intermediate target values for a
+ * saturation + brightness bitmap and applies them
+ * indirectly via the `apply` method.
+ *
+ * @note Was ToPercentGray in SSCI.
+ */
+ bool updateSaturationAndBrightness();
+
+ /**
+ * Computes and applies the final values to the
+ * `_remaps` map.
+ *
+ * @note In SSCI, a boolean array of changed values
+ * was passed into this method, but this was done by
+ * creating arrays on the stack in the caller. Instead
+ * of doing this, we simply add another member property
+ * `_idealColorsChanged` and use that instead.
+ */
+ bool apply();
+
+ /**
+ * Calculates the square distance of two colors.
+ *
+ * @note In SSCI this method is Rgb24::Dist, but it is
+ * only used by SingleRemap.
+ */
+ int colorDistance(const Color &a, const Color &b) const;
+
+ /**
+ * Finds the closest index in the next palette matching
+ * the given RGB color. Returns -1 if no match can be
+ * found that is closer than `minimumDistance`.
+ *
+ * @note In SSCI, this method is SOLPalette::Match, but
+ * this particular signature is only used by
+ * SingleRemap.
+ */
+ int16 matchColor(const Color &color, const int minimumDistance, int &outDistance, const bool *const blockedIndexes) const;
+};
+
+#pragma mark -
+#pragma mark GfxRemap32
+
+/**
+ * This class provides color remapping support for SCI32
+ * games.
+ */
+class GfxRemap32 : public Common::Serializable {
+public:
+ GfxRemap32();
+
+ void saveLoadWithSerializer(Common::Serializer &s);
+
+ inline uint8 getRemapCount() const { return _numActiveRemaps; }
+ inline uint8 getStartColor() const { return _remapStartColor; }
+ inline uint8 getEndColor() const { return _remapEndColor; }
+ inline uint8 getBlockedRangeStart() const { return _blockedRangeStart; }
+ inline int16 getBlockedRangeCount() const { return _blockedRangeCount; }
+
+ /**
+ * Turns off remapping of the given color. If `color` is
+ * 0, all remaps are turned off.
+ */
+ void remapOff(const uint8 color);
+
+ /**
+ * Turns off all color remaps.
+ */
+ void remapAllOff();
+
+ /**
+ * Configures a SingleRemap for the remap color `color`.
+ * The SingleRemap will shift palette colors between
+ * `from` and `to` (inclusive) by `delta` palette
+ * entries when the remap is applied.
+ */
+ void remapByRange(const uint8 color, const int16 from, const int16 to, const int16 delta);
+
+ /**
+ * Configures a SingleRemap for the remap color `color`
+ * to modify the brightness of remapped colors by
+ * `percent`.
+ */
+ void remapByPercent(const uint8 color, const int16 percent);
+
+ /**
+ * Configures a SingleRemap for the remap color `color`
+ * to modify the saturation of remapped colors by
+ * `gray`.
+ */
+ void remapToGray(const uint8 color, const int8 gray);
+
+ /**
+ * Configures a SingleRemap for the remap color `color`
+ * to modify the brightness of remapped colors by
+ * `percent`, and saturation of remapped colors by
+ * `gray`.
+ */
+ void remapToPercentGray(const uint8 color, const int16 gray, const int16 percent);
+
+ /**
+ * Prevents GfxRemap32 from using the given range of
+ * palette entries as potential remap targets.
+ *
+ * @NOTE Was DontMapToRange in SSCI.
+ */
+ void blockRange(const uint8 from, const int16 count);
+
+ /**
+ * Determines whether or not the given color has an
+ * active remapper. If it does not, it is treated as a
+ * skip color and the pixel is not drawn.
+ *
+ * @note SSCI uses a boolean array to decide whether a
+ * a pixel is remapped, but it is possible to get the
+ * same information from `_remaps`, as this function
+ * does.
+ * Presumably, the separate array was created for
+ * performance reasons, since this is called a lot in
+ * the most critical section of the renderer.
+ */
+ inline bool remapEnabled(uint8 color) const {
+ const uint8 index = _remapEndColor - color;
+ assert(index < _remaps.size());
+ return (_remaps[index]._type != kRemapNone);
+ }
+
+ /**
+ * Calculates the correct color for a target by looking
+ * up the target color in the SingleRemap that controls
+ * the given sourceColor. If there is no remap for the
+ * given color, it will be treated as a skip color.
+ */
+ inline uint8 remapColor(const uint8 sourceColor, const uint8 targetColor) const {
+ const uint8 index = _remapEndColor - sourceColor;
+ assert(index < _remaps.size());
+ const SingleRemap &singleRemap = _remaps[index];
+ assert(singleRemap._type != kRemapNone);
+ return singleRemap._remapColors[targetColor];
+ }
+
+ /**
+ * Updates all active remaps in response to a palette
+ * change or a remap settings change.
+ *
+ * `paletteChanged` is true if the next palette in
+ * GfxPalette32 has been previously modified by other
+ * palette operations.
+ */
+ bool remapAllTables(const bool paletteUpdated);
+
+private:
+ typedef Common::Array<SingleRemap> SingleRemapsList;
+
+ /**
+ * The first index of the remap area in the system
+ * palette.
+ */
+ const uint8 _remapStartColor;
+
+ /**
+ * The last index of the remap area in the system
+ * palette.
+ */
+ uint8 _remapEndColor;
+
+ /**
+ * The number of currently active remaps.
+ */
+ uint8 _numActiveRemaps;
+
+ /**
+ * The list of SingleRemaps.
+ */
+ SingleRemapsList _remaps;
+
+ /**
+ * If true, indicates that one or more SingleRemaps were
+ * reconfigured and all remaps need to be recalculated.
+ */
+ bool _needsUpdate;
+
+ /**
+ * The first color that is blocked from being used as a
+ * remap target color.
+ */
+ uint8 _blockedRangeStart;
+
+ /**
+ * The size of the range of blocked colors. If zero,
+ * all colors are potential targets for remapping.
+ */
+ int16 _blockedRangeCount;
+};
+} // End of namespace Sci
+#endif
diff --git a/engines/sci/graphics/screen_item32.cpp b/engines/sci/graphics/screen_item32.cpp
index 0bbb056071..7383dc222e 100644
--- a/engines/sci/graphics/screen_item32.cpp
+++ b/engines/sci/graphics/screen_item32.cpp
@@ -42,7 +42,8 @@ _pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {
+_mirrorX(false),
+_drawBlackLines(false) {
SegManager *segMan = g_sci->getEngineState()->_segMan;
setFromObject(segMan, object, true, true);
@@ -55,14 +56,15 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(0, 0),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {}
+_mirrorX(false),
+_drawBlackLines(false) {}
ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect) :
_plane(plane),
@@ -70,34 +72,36 @@ _useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
+_fixedPriority(false),
_position(rect.left, rect.top),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {
+_mirrorX(false),
+_drawBlackLines(false) {
if (celInfo.type == kCelTypeColor) {
_insetRect = rect;
}
}
-ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect, const ScaleInfo &scaleInfo) :
+ScreenItem::ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo) :
_plane(plane),
_scale(scaleInfo),
_useInsetRect(false),
_z(0),
_celInfo(celInfo),
_celObj(nullptr),
-_fixPriority(false),
-_position(rect.left, rect.top),
+_fixedPriority(false),
+_position(position),
_object(make_reg(0, _nextObjectId++)),
_pictureId(-1),
_created(g_sci->_gfxFrameout->getScreenCount()),
_updated(0),
_deleted(0),
-_mirrorX(false) {}
+_mirrorX(false),
+_drawBlackLines(false) {}
ScreenItem::ScreenItem(const ScreenItem &other) :
_plane(other._plane),
@@ -108,14 +112,25 @@ _celObj(nullptr),
_object(other._object),
_mirrorX(other._mirrorX),
_scaledPosition(other._scaledPosition),
-_screenRect(other._screenRect) {
+_screenRect(other._screenRect),
+_drawBlackLines(other._drawBlackLines) {
if (other._useInsetRect) {
_insetRect = other._insetRect;
}
}
void ScreenItem::operator=(const ScreenItem &other) {
- _celInfo = other._celInfo;
+ // NOTE: The original engine did not check for differences in `_celInfo`
+ // to clear `_celObj` here; instead, it unconditionally set `_celInfo`,
+ // didn't clear `_celObj`, and did hacky stuff in `kIsOnMe` to avoid
+ // testing a mismatched `_celObj`. See `GfxFrameout::kernelIsOnMe` for
+ // more detail.
+ if (_celInfo != other._celInfo) {
+ _celInfo = other._celInfo;
+ delete _celObj;
+ _celObj = nullptr;
+ }
+
_screenRect = other._screenRect;
_mirrorX = other._mirrorX;
_useInsetRect = other._useInsetRect;
@@ -124,6 +139,11 @@ void ScreenItem::operator=(const ScreenItem &other) {
}
_scale = other._scale;
_scaledPosition = other._scaledPosition;
+ _drawBlackLines = other._drawBlackLines;
+}
+
+ScreenItem::~ScreenItem() {
+ delete _celObj;
}
void ScreenItem::init() {
@@ -195,10 +215,10 @@ void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const boo
}
if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
- _fixPriority = true;
+ _fixedPriority = true;
_priority = readSelectorValue(segMan, object, SELECTOR(priority));
} else {
- _fixPriority = false;
+ _fixedPriority = false;
writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
}
@@ -224,7 +244,9 @@ void ScreenItem::calcRects(const Plane &plane) {
const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
- Common::Rect celRect(_celObj->_width, _celObj->_height);
+ const CelObj &celObj = getCelObj();
+
+ Common::Rect celRect(celObj._width, celObj._height);
if (_useInsetRect) {
if (_insetRect.intersects(celRect)) {
_insetRect.clip(celRect);
@@ -235,28 +257,35 @@ void ScreenItem::calcRects(const Plane &plane) {
_insetRect = celRect;
}
- Ratio newRatioX;
- Ratio newRatioY;
+ Ratio scaleX, scaleY;
if (_scale.signal & kScaleSignalDoScaling32) {
if (_scale.signal & kScaleSignalUseVanishingPoint) {
int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y);
- newRatioX = Ratio(num, 128);
- newRatioY = Ratio(num, 128);
+ scaleX = Ratio(num, 128);
+ scaleY = Ratio(num, 128);
} else {
- newRatioX = Ratio(_scale.x, 128);
- newRatioY = Ratio(_scale.y, 128);
+ scaleX = Ratio(_scale.x, 128);
+ scaleY = Ratio(_scale.y, 128);
}
}
- if (newRatioX.getNumerator() && newRatioY.getNumerator()) {
+ if (scaleX.getNumerator() && scaleY.getNumerator()) {
_screenItemRect = _insetRect;
- if (_celObj->_scaledWidth != scriptWidth || _celObj->_scaledHeight != scriptHeight) {
+ const Ratio celToScreenX(screenWidth, celObj._scaledWidth);
+ const Ratio celToScreenY(screenHeight, celObj._scaledHeight);
+
+ // Cel may use a coordinate system that is not the same size as the
+ // script coordinate system (usually this means high-resolution
+ // pictures with low-resolution scripts)
+ if (celObj._scaledWidth != kLowResX || celObj._scaledHeight != kLowResY) {
+ // high resolution coordinates
+
if (_useInsetRect) {
- Ratio celScriptXRatio(_celObj->_scaledWidth, scriptWidth);
- Ratio celScriptYRatio(_celObj->_scaledHeight, scriptHeight);
- mulru(_screenItemRect, celScriptXRatio, celScriptYRatio);
+ const Ratio scriptToCelX(celObj._scaledWidth, scriptWidth);
+ const Ratio scriptToCelY(celObj._scaledHeight, scriptHeight);
+ mulru(_screenItemRect, scriptToCelX, scriptToCelY, 0);
if (_screenItemRect.intersects(celRect)) {
_screenItemRect.clip(celRect);
@@ -265,53 +294,76 @@ void ScreenItem::calcRects(const Plane &plane) {
}
}
- int displaceX = _celObj->_displace.x;
- int displaceY = _celObj->_displace.y;
+ int displaceX = celObj._displace.x;
+ int displaceY = celObj._displace.y;
- if (_mirrorX != _celObj->_mirrorX && _celInfo.type != kCelTypePic) {
- displaceX = _celObj->_width - _celObj->_displace.x - 1;
+ if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) {
+ displaceX = celObj._width - celObj._displace.x - 1;
}
- if (!newRatioX.isOne() || !newRatioY.isOne()) {
- mulru(_screenItemRect, newRatioX, newRatioY);
- displaceX = (displaceX * newRatioX).toInt();
- displaceY = (displaceY * newRatioY).toInt();
- }
+ if (!scaleX.isOne() || !scaleY.isOne()) {
+ // Different games use a different cel scaling mode, but the
+ // difference isn't consistent across SCI versions; instead,
+ // it seems to be related to an update that happened during
+ // SCI2.1mid where games started using hi-resolution game
+ // scripts
+ if (scriptWidth == kLowResX) {
+ mulinc(_screenItemRect, scaleX, scaleY);
+ } else {
+ _screenItemRect.left = (_screenItemRect.left * scaleX).toInt();
+ _screenItemRect.top = (_screenItemRect.top * scaleY).toInt();
+
+ if (scaleX.getNumerator() > scaleX.getDenominator()) {
+ _screenItemRect.right = (_screenItemRect.right * scaleX).toInt();
+ } else {
+ _screenItemRect.right = ((_screenItemRect.right - 1) * scaleX).toInt() + 1;
+ }
+
+ if (scaleY.getNumerator() > scaleY.getDenominator()) {
+ _screenItemRect.bottom = (_screenItemRect.bottom * scaleY).toInt();
+ } else {
+ _screenItemRect.bottom = ((_screenItemRect.bottom - 1) * scaleY).toInt() + 1;
+ }
+ }
- Ratio celXRatio(screenWidth, _celObj->_scaledWidth);
- Ratio celYRatio(screenHeight, _celObj->_scaledHeight);
+ displaceX = (displaceX * scaleX).toInt();
+ displaceY = (displaceY * scaleY).toInt();
+ }
- displaceX = (displaceX * celXRatio).toInt();
- displaceY = (displaceY * celYRatio).toInt();
+ mulinc(_screenItemRect, celToScreenX, celToScreenY);
+ displaceX = (displaceX * celToScreenX).toInt();
+ displaceY = (displaceY * celToScreenY).toInt();
- mulru(_screenItemRect, celXRatio, celYRatio);
+ const Ratio scriptToScreenX = Ratio(screenWidth, scriptWidth);
+ const Ratio scriptToScreenY = Ratio(screenHeight, scriptHeight);
if (/* TODO: dword_C6288 */ false && _celInfo.type == kCelTypePic) {
_scaledPosition.x = _position.x;
_scaledPosition.y = _position.y;
} else {
- _scaledPosition.x = (_position.x * screenWidth / scriptWidth) - displaceX;
- _scaledPosition.y = (_position.y * screenHeight / scriptHeight) - displaceY;
+ _scaledPosition.x = (_position.x * scriptToScreenX).toInt() - displaceX;
+ _scaledPosition.y = (_position.y * scriptToScreenY).toInt() - displaceY;
}
_screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
- if (_mirrorX != _celObj->_mirrorX && _celInfo.type == kCelTypePic) {
+ if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) {
Common::Rect temp(_insetRect);
- if (!newRatioX.isOne()) {
- mulru(temp, newRatioX, Ratio());
+ if (!scaleX.isOne()) {
+ mulinc(temp, scaleX, Ratio());
}
- mulru(temp, celXRatio, Ratio());
+ mulinc(temp, celToScreenX, Ratio());
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
+ if (celObjPic == nullptr) {
+ error("Expected a CelObjPic");
+ }
+ temp.translate((celObjPic->_relativePosition.x * scriptToScreenX).toInt() - displaceX, 0);
- temp.translate(celObjPic->_relativePosition.x * screenWidth / scriptWidth - displaceX, 0);
-
- // TODO: This is weird, and probably wrong calculation of widths
- // due to BR-inclusion
- int deltaX = plane._planeRect.right - plane._planeRect.left + 1 - temp.right - 1 - temp.left;
+ // TODO: This is weird.
+ int deltaX = plane._planeRect.width() - temp.right - 1 - temp.left;
_scaledPosition.x += deltaX;
_screenItemRect.translate(deltaX, 0);
@@ -321,41 +373,45 @@ void ScreenItem::calcRects(const Plane &plane) {
_scaledPosition.y += plane._planeRect.top;
_screenItemRect.translate(plane._planeRect.left, plane._planeRect.top);
- _ratioX = newRatioX * Ratio(screenWidth, _celObj->_scaledWidth);
- _ratioY = newRatioY * Ratio(screenHeight, _celObj->_scaledHeight);
+ _ratioX = scaleX * celToScreenX;
+ _ratioY = scaleY * celToScreenY;
} else {
- int displaceX = _celObj->_displace.x;
- if (_mirrorX != _celObj->_mirrorX && _celInfo.type != kCelTypePic) {
- displaceX = _celObj->_width - _celObj->_displace.x - 1;
+ // low resolution coordinates
+
+ int displaceX = celObj._displace.x;
+ if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) {
+ displaceX = celObj._width - celObj._displace.x - 1;
}
- if (!newRatioX.isOne() || !newRatioY.isOne()) {
- mulru(_screenItemRect, newRatioX, newRatioY);
+ if (!scaleX.isOne() || !scaleY.isOne()) {
+ mulinc(_screenItemRect, scaleX, scaleY);
// TODO: This was in the original code, baked into the
- // multiplication though it is not immediately clear
+ // multiplication though it is not immediately clear
// why this is the only one that reduces the BR corner
_screenItemRect.right -= 1;
_screenItemRect.bottom -= 1;
}
- _scaledPosition.x = _position.x - (displaceX * newRatioX).toInt();
- _scaledPosition.y = _position.y - (_celObj->_displace.y * newRatioY).toInt();
+ _scaledPosition.x = _position.x - (displaceX * scaleX).toInt();
+ _scaledPosition.y = _position.y - (celObj._displace.y * scaleY).toInt();
_screenItemRect.translate(_scaledPosition.x, _scaledPosition.y);
- if (_mirrorX != _celObj->_mirrorX && _celInfo.type == kCelTypePic) {
+ if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) {
Common::Rect temp(_insetRect);
- if (!newRatioX.isOne()) {
- mulru(temp, newRatioX, Ratio());
+ if (!scaleX.isOne()) {
+ mulinc(temp, scaleX, Ratio());
temp.right -= 1;
}
CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj);
- temp.translate(celObjPic->_relativePosition.x - (displaceX * newRatioX).toInt(), celObjPic->_relativePosition.y - (_celObj->_displace.y * newRatioY).toInt());
+ if (celObjPic == nullptr) {
+ error("Expected a CelObjPic");
+ }
+ temp.translate(celObjPic->_relativePosition.x - (displaceX * scaleX).toInt(), celObjPic->_relativePosition.y - (celObj._displace.y * scaleY).toInt());
- // TODO: This is weird, and probably wrong calculation of widths
- // due to BR-inclusion
- int deltaX = plane._gameRect.right - plane._gameRect.left + 1 - temp.right - 1 - temp.left;
+ // TODO: This is weird.
+ int deltaX = plane._gameRect.width() - temp.right - 1 - temp.left;
_scaledPosition.x += deltaX;
_screenItemRect.translate(deltaX, 0);
@@ -365,15 +421,13 @@ void ScreenItem::calcRects(const Plane &plane) {
_scaledPosition.y += plane._gameRect.top;
_screenItemRect.translate(plane._gameRect.left, plane._gameRect.top);
- if (screenWidth != _celObj->_scaledWidth || _celObj->_scaledHeight != screenHeight) {
- Ratio celXRatio(screenWidth, _celObj->_scaledWidth);
- Ratio celYRatio(screenHeight, _celObj->_scaledHeight);
- mulru(_scaledPosition, celXRatio, celYRatio);
- mulru(_screenItemRect, celXRatio, celYRatio);
+ if (celObj._scaledWidth != screenWidth || celObj._scaledHeight != screenHeight) {
+ mulru(_scaledPosition, celToScreenX, celToScreenY);
+ mulru(_screenItemRect, celToScreenX, celToScreenY, 1);
}
- _ratioX = newRatioX * Ratio(screenWidth, _celObj->_scaledWidth);
- _ratioY = newRatioY * Ratio(screenHeight, _celObj->_scaledHeight);
+ _ratioX = scaleX * celToScreenX;
+ _ratioY = scaleY * celToScreenY;
}
_screenRect = _screenItemRect;
@@ -387,7 +441,7 @@ void ScreenItem::calcRects(const Plane &plane) {
_screenRect.top = 0;
}
- if (!_fixPriority) {
+ if (!_fixedPriority) {
_priority = _z + _position.y;
}
} else {
@@ -398,7 +452,7 @@ void ScreenItem::calcRects(const Plane &plane) {
}
}
-CelObj &ScreenItem::getCelObj() {
+CelObj &ScreenItem::getCelObj() const {
if (_celObj == nullptr) {
switch (_celInfo.type) {
case kCelTypeView:
@@ -420,7 +474,7 @@ CelObj &ScreenItem::getCelObj() {
}
void ScreenItem::printDebugInfo(Console *con) const {
- con->debugPrintf("%x:%x (%s), prio %d, x %d, y %d, z: %d, scaledX: %d, scaledY: %d flags: %d\n",
+ con->debugPrintf("%04x:%04x (%s), prio %d, x %d, y %d, z: %d, scaledX: %d, scaledY: %d flags: %d\n",
_object.getSegment(), _object.getOffset(),
g_sci->getEngineState()->_segMan->getObjectName(_object),
_priority,
@@ -494,6 +548,146 @@ void ScreenItem::update(const reg_t object) {
_deleted = 0;
}
+void ScreenItem::update() {
+ Plane *plane = g_sci->_gfxFrameout->getPlanes().findByObject(_plane);
+ if (plane == nullptr) {
+ error("ScreenItem::update: Invalid plane %04x:%04x", PRINT_REG(_plane));
+ }
+
+ if (plane->_screenItemList.findByObject(_object) == nullptr) {
+ error("ScreenItem::update: %04x:%04x not in plane %04x:%04x", PRINT_REG(_object), PRINT_REG(_plane));
+ }
+
+ if (!_created) {
+ _updated = g_sci->_gfxFrameout->getScreenCount();
+ }
+ _deleted = 0;
+
+ delete _celObj;
+ _celObj = nullptr;
+}
+
+Common::Rect ScreenItem::getNowSeenRect(const Plane &plane) const {
+ CelObj &celObj = getCelObj();
+
+ Common::Rect celObjRect(celObj._width, celObj._height);
+ Common::Rect nsRect;
+
+ if (_useInsetRect) {
+ if (_insetRect.intersects(celObjRect)) {
+ nsRect = _insetRect;
+ nsRect.clip(celObjRect);
+ } else {
+ nsRect = Common::Rect();
+ }
+ } else {
+ nsRect = celObjRect;
+ }
+
+ const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ Ratio scaleX, scaleY;
+ if (_scale.signal & kScaleSignalDoScaling32) {
+ if (_scale.signal & kScaleSignalUseVanishingPoint) {
+ int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y);
+ scaleX = Ratio(num, 128);
+ scaleY = Ratio(num, 128);
+ } else {
+ scaleX = Ratio(_scale.x, 128);
+ scaleY = Ratio(_scale.y, 128);
+ }
+ }
+
+ if (scaleX.getNumerator() == 0 || scaleY.getNumerator() == 0) {
+ return Common::Rect();
+ }
+
+ int16 displaceX = celObj._displace.x;
+ int16 displaceY = celObj._displace.y;
+
+ if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) {
+ displaceX = celObj._width - displaceX - 1;
+ }
+
+ if (celObj._scaledWidth != kLowResX || celObj._scaledHeight != kLowResY) {
+ // high resolution coordinates
+
+ if (_useInsetRect) {
+ Ratio scriptToCelX(celObj._scaledWidth, scriptWidth);
+ Ratio scriptToCelY(celObj._scaledHeight, scriptHeight);
+ mulru(nsRect, scriptToCelX, scriptToCelY, 0);
+
+ if (nsRect.intersects(celObjRect)) {
+ nsRect.clip(celObjRect);
+ } else {
+ nsRect = Common::Rect();
+ }
+ }
+
+ if (!scaleX.isOne() || !scaleY.isOne()) {
+ // Different games use a different cel scaling mode, but the
+ // difference isn't consistent across SCI versions; instead,
+ // it seems to be related to an update that happened during
+ // SCI2.1mid where games started using hi-resolution game
+ // scripts
+ if (scriptWidth == kLowResX) {
+ mulinc(nsRect, scaleX, scaleY);
+ // TODO: This was in the original code, baked into the
+ // multiplication though it is not immediately clear
+ // why this is the only one that reduces the BR corner
+ nsRect.right -= 1;
+ nsRect.bottom -= 1;
+ } else {
+ nsRect.left = (nsRect.left * scaleX).toInt();
+ nsRect.top = (nsRect.top * scaleY).toInt();
+
+ if (scaleX.getNumerator() > scaleX.getDenominator()) {
+ nsRect.right = (nsRect.right * scaleX).toInt();
+ } else {
+ nsRect.right = ((nsRect.right - 1) * scaleX).toInt() + 1;
+ }
+
+ if (scaleY.getNumerator() > scaleY.getDenominator()) {
+ nsRect.bottom = (nsRect.bottom * scaleY).toInt();
+ } else {
+ nsRect.bottom = ((nsRect.bottom - 1) * scaleY).toInt() + 1;
+ }
+ }
+ }
+
+ Ratio celToScriptX(scriptWidth, celObj._scaledWidth);
+ Ratio celToScriptY(scriptHeight, celObj._scaledHeight);
+
+ displaceX = (displaceX * scaleX * celToScriptX).toInt();
+ displaceY = (displaceY * scaleY * celToScriptY).toInt();
+
+ mulinc(nsRect, celToScriptX, celToScriptY);
+ nsRect.translate(_position.x - displaceX, _position.y - displaceY);
+ } else {
+ // low resolution coordinates
+
+ if (!scaleX.isOne() || !scaleY.isOne()) {
+ mulinc(nsRect, scaleX, scaleY);
+ // TODO: This was in the original code, baked into the
+ // multiplication though it is not immediately clear
+ // why this is the only one that reduces the BR corner
+ nsRect.right -= 1;
+ nsRect.bottom -= 1;
+ }
+
+ displaceX = (displaceX * scaleX).toInt();
+ displaceY = (displaceY * scaleY).toInt();
+ nsRect.translate(_position.x - displaceX, _position.y - displaceY);
+
+ if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) {
+ nsRect.translate(plane._gameRect.width() - nsRect.width(), 0);
+ }
+ }
+
+ return nsRect;
+}
+
#pragma mark -
#pragma mark ScreenItemList
ScreenItem *ScreenItemList::findByObject(const reg_t object) const {
@@ -506,24 +700,44 @@ ScreenItem *ScreenItemList::findByObject(const reg_t object) const {
return *screenItemIt;
}
void ScreenItemList::sort() {
- // TODO: SCI engine used _unsorted as an array of indexes into the
- // list itself and then performed the same swap operations on the
- // _unsorted array as the _storage array during sorting, but the
- // only reason to do this would be if some of the pointers in the
- // list were replaced so the pointer values themselves couldn’t
- // simply be recorded and then restored later. It is not yet
- // verified whether this simplification of the sort/unsort is
- // safe.
+ if (size() < 2) {
+ return;
+ }
+
for (size_type i = 0; i < size(); ++i) {
- _unsorted[i] = (*this)[i];
+ _unsorted[i] = i;
}
- Common::sort(begin(), end(), sortHelper);
+ for (size_type i = size() - 1; i > 0; --i) {
+ bool swap = false;
+
+ for (size_type j = 0; j < i; ++j) {
+ value_type &a = operator[](j);
+ value_type &b = operator[](j + 1);
+
+ if (a == nullptr || *a > *b) {
+ SWAP(a, b);
+ SWAP(_unsorted[j], _unsorted[j + 1]);
+ swap = true;
+ }
+ }
+
+ if (!swap) {
+ break;
+ }
+ }
}
void ScreenItemList::unsort() {
+ if (size() < 2) {
+ return;
+ }
+
for (size_type i = 0; i < size(); ++i) {
- (*this)[i] = _unsorted[i];
+ while (_unsorted[i] != i) {
+ SWAP(operator[](_unsorted[i]), operator[](i));
+ SWAP(_unsorted[_unsorted[i]], _unsorted[i]);
+ }
}
}
-}
+} // End of namespace Sci
diff --git a/engines/sci/graphics/screen_item32.h b/engines/sci/graphics/screen_item32.h
index 0ca840a13a..3d9d5ef3d7 100644
--- a/engines/sci/graphics/screen_item32.h
+++ b/engines/sci/graphics/screen_item32.h
@@ -64,12 +64,12 @@ private:
*/
static uint16 _nextObjectId;
+public:
/**
* The parent plane of this screen item.
*/
reg_t _plane;
-public:
/**
* Scaling data used to calculate the final screen
* dimensions of the screen item as well as the scaling
@@ -88,15 +88,23 @@ private:
Common::Rect _screenItemRect;
/**
- * TODO: Document
+ * If true, the `_insetRect` rectangle will be used
+ * when calculating the dimensions of the screen item
+ * instead of the cel's intrinsic width and height.
+ *
+ * In other words, using an inset rect means that
+ * the cel is cropped to the dimensions given in
+ * `_insetRect`.
*/
bool _useInsetRect;
/**
- * TODO: Documentation
- * The insetRect is also used to describe the fill
- * rectangle of a screen item that is drawn using
- * CelObjColor.
+ * The cropping rectangle used when `_useInsetRect`
+ * is true.
+ *
+ * `_insetRect` is also used to describe the fill
+ * rectangle of a screen item with a CelObjColor
+ * cel.
*/
Common::Rect _insetRect;
@@ -125,14 +133,14 @@ public:
* item. This member is populated by calling
* `getCelObj`.
*/
- CelObj *_celObj;
+ mutable CelObj *_celObj;
/**
* If set, the priority for this screen item is fixed
* in place. Otherwise, the priority of the screen item
* is calculated from its y-position + z-index.
*/
- bool _fixPriority;
+ bool _fixedPriority;
/**
* The rendering priority of the screen item, relative
@@ -172,7 +180,7 @@ public:
* plane is a pic type and its picture resource ID has
* changed
*/
- int _created, _updated, _deleted; // ?
+ int _created, _updated, _deleted;
/**
* For screen items that represent picture cels, this
@@ -206,6 +214,14 @@ public:
Common::Rect _screenRect;
/**
+ * Whether or not the screen item should be drawn
+ * with black lines drawn every second line. This is
+ * used when pixel doubling videos to improve apparent
+ * sharpness at the cost of your eyesight.
+ */
+ bool _drawBlackLines;
+
+ /**
* Initialises static Plane members.
*/
static void init();
@@ -213,8 +229,9 @@ public:
ScreenItem(const reg_t screenItem);
ScreenItem(const reg_t plane, const CelInfo32 &celInfo);
ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect);
- ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Rect &rect, const ScaleInfo &scaleInfo);
+ ScreenItem(const reg_t plane, const CelInfo32 &celInfo, const Common::Point &position, const ScaleInfo &scaleInfo);
ScreenItem(const ScreenItem &other);
+ ~ScreenItem();
void operator=(const ScreenItem &);
inline bool operator<(const ScreenItem &other) const {
@@ -228,9 +245,25 @@ public:
}
if (_position.y + _z == other._position.y + other._z) {
- return false;
- // TODO: Failure in SQ6 room 220
-// return _object < other._object;
+ return _object < other._object;
+ }
+ }
+
+ return false;
+ }
+
+ inline bool operator>(const ScreenItem &other) const {
+ if (_priority > other._priority) {
+ return true;
+ }
+
+ if (_priority == other._priority) {
+ if (_position.y + _z > other._position.y + other._z) {
+ return true;
+ }
+
+ if (_position.y + _z == other._position.y + other._z) {
+ return _object > other._object;
}
}
@@ -251,7 +284,7 @@ public:
* screen item. If a cel object does not already exist,
* one will be created and assigned.
*/
- CelObj &getCelObj();
+ CelObj &getCelObj() const;
void printDebugInfo(Console *con) const;
@@ -260,6 +293,19 @@ public:
* VM object.
*/
void update(const reg_t object);
+
+ /**
+ * Updates the properties of the screen item for one not belonging
+ * to a VM object. Originally GraphicsMgr::UpdateScreenItem.
+ */
+ void update();
+
+ /**
+ * Gets the "now seen" rect for the screen item, which
+ * represents the current size and position of the
+ * screen item on the screen in script coordinates.
+ */
+ Common::Rect getNowSeenRect(const Plane &plane) const;
};
#pragma mark -
@@ -267,16 +313,14 @@ public:
typedef StablePointerArray<ScreenItem, 250> ScreenItemListBase;
class ScreenItemList : public ScreenItemListBase {
- static bool inline sortHelper(const ScreenItem *a, const ScreenItem *b) {
- return *a < *b;
- }
-public:
- ScreenItem *_unsorted[250];
+private:
+ size_type _unsorted[250];
+public:
ScreenItem *findByObject(const reg_t object) const;
void sort();
void unsort();
};
-}
+} // End of namespace Sci
#endif
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index eabc329ee0..277e6e93d0 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -29,6 +29,7 @@
#include "sci/engine/selector.h"
#include "sci/engine/state.h"
#include "sci/graphics/cache.h"
+#include "sci/graphics/celobj32.h"
#include "sci/graphics/compare.h"
#include "sci/graphics/font.h"
#include "sci/graphics/frameout.h"
@@ -37,51 +38,29 @@
namespace Sci {
-#define BITMAP_HEADER_SIZE 46
+int16 GfxText32::_defaultFontId = 0;
+int16 GfxText32::_scaledWidth = 0;
+int16 GfxText32::_scaledHeight = 0;
-GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) :
+GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts) :
_segMan(segMan),
_cache(fonts),
- _screen(screen),
- _scaledWidth(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth),
- _scaledHeight(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight),
- _bitmap(NULL_REG) {}
-
-void GfxText32::buildBitmapHeader(byte *bitmap, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool useRemap) const {
-
- WRITE_SCI11ENDIAN_UINT16(bitmap + 0, width);
- WRITE_SCI11ENDIAN_UINT16(bitmap + 2, height);
- WRITE_SCI11ENDIAN_UINT16(bitmap + 4, (uint16)displaceX);
- WRITE_SCI11ENDIAN_UINT16(bitmap + 6, (uint16)displaceY);
- bitmap[8] = skipColor;
- bitmap[9] = 0;
- WRITE_SCI11ENDIAN_UINT16(bitmap + 10, 0);
-
- if (useRemap) {
- bitmap[10] |= 2;
+ // Not a typo, the original engine did not initialise height, only width
+ _width(0),
+ _text(""),
+ _bitmap(NULL_REG) {
+ _fontId = _defaultFontId;
+ _font = _cache->getFont(_defaultFontId);
+
+ if (_scaledWidth == 0) {
+ // initialize the statics
+ _scaledWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ _scaledHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ }
}
- WRITE_SCI11ENDIAN_UINT32(bitmap + 12, width * height);
- WRITE_SCI11ENDIAN_UINT32(bitmap + 16, 0);
-
- if (hunkPaletteOffset) {
- WRITE_SCI11ENDIAN_UINT32(bitmap + 20, hunkPaletteOffset + BITMAP_HEADER_SIZE);
- } else {
- WRITE_SCI11ENDIAN_UINT32(bitmap + 20, 0);
- }
+reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling) {
- WRITE_SCI11ENDIAN_UINT32(bitmap + 24, BITMAP_HEADER_SIZE);
- WRITE_SCI11ENDIAN_UINT32(bitmap + 28, BITMAP_HEADER_SIZE);
- WRITE_SCI11ENDIAN_UINT32(bitmap + 32, 0);
- WRITE_SCI11ENDIAN_UINT16(bitmap + 36, scaledWidth);
- WRITE_SCI11ENDIAN_UINT16(bitmap + 38, scaledHeight);
-}
-
-int16 GfxText32::_defaultFontId = 0;
-
-reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling, reg_t *outBitmapObject) {
-
- _field_22 = 0;
_borderColor = borderColor;
_text = text;
_textRect = rect;
@@ -93,10 +72,7 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
_alignment = alignment;
_dimmed = dimmed;
- if (fontId != _fontId) {
- _fontId = fontId == -1 ? _defaultFontId : fontId;
- _font = _cache->getFont(_fontId);
- }
+ setFont(fontId);
if (doScaling) {
int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
@@ -107,7 +83,7 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
_width = (_width * scaleX).toInt();
_height = (_height * scaleY).toInt();
- mul(_textRect, scaleX, scaleY);
+ mulinc(_textRect, scaleX, scaleY);
}
// _textRect represents where text is drawn inside the
@@ -120,10 +96,8 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
_textRect = Common::Rect();
}
- _bitmap = _segMan->allocateHunkEntry("FontBitmap()", _width * _height + BITMAP_HEADER_SIZE);
-
- byte *bitmap = _segMan->getHunkPointer(_bitmap);
- buildBitmapHeader(bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false);
+ BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false);
+ _bitmap = bitmap.getObject();
erase(bitmapRect, false);
@@ -132,461 +106,614 @@ reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect
}
drawTextBox();
+ return _bitmap;
+}
+
+reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed) {
+ _borderColor = borderColor;
+ _text = text;
+ _textRect = rect;
+ _foreColor = foreColor;
+ _dimmed = dimmed;
+
+ setFont(fontId);
+
+ int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ mulinc(_textRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight));
+
+ CelObjView view(celInfo.resourceId, celInfo.loopNo, celInfo.celNo);
+ _skipColor = view._transparentColor;
+ _width = view._width * _scaledWidth / view._scaledWidth;
+ _height = view._height * _scaledHeight / view._scaledHeight;
+
+ Common::Rect bitmapRect(_width, _height);
+ if (_textRect.intersects(bitmapRect)) {
+ _textRect.clip(bitmapRect);
+ } else {
+ _textRect = Common::Rect();
+ }
+
+ BitmapResource bitmap(_segMan, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false);
+ _bitmap = bitmap.getObject();
+
+ // NOTE: The engine filled the bitmap pixels with 11 here, which is silly
+ // because then it just erased the bitmap using the skip color. So we don't
+ // fill the bitmap redundantly here.
- debug("Drawing a bitmap %dx%d, scaled %dx%d, border %d, font %d", width, height, _width, _height, _borderColor, _fontId);
+ _backColor = _skipColor;
+ erase(bitmapRect, false);
+ _backColor = backColor;
+
+ view.draw(bitmap.getBuffer(), bitmapRect, Common::Point(0, 0), false, Ratio(_scaledWidth, view._scaledWidth), Ratio(_scaledHeight, view._scaledHeight));
+
+ if (_backColor != skipColor && _foreColor != skipColor) {
+ erase(_textRect, false);
+ }
+
+ if (text.size() > 0) {
+ if (_foreColor == skipColor) {
+ error("TODO: Implement transparent text");
+ } else {
+ if (borderColor != -1) {
+ drawFrame(bitmapRect, 1, _borderColor, false);
+ }
+
+ drawTextBox();
+ }
+ }
- *outBitmapObject = _bitmap;
return _bitmap;
}
-reg_t GfxText32::createTitledFontBitmap(CelInfo32 &celInfo, Common::Rect &rect, Common::String &text, int16 foreColor, int16 backColor, int font, int16 skipColor, int16 borderColor, bool dimmed, void *unknown1) {
- warning("TODO: createTitledFontBitmap");
- return NULL_REG;
+void GfxText32::setFont(const GuiResourceId fontId) {
+ // NOTE: In SCI engine this calls FontMgr::BuildFontTable and then a font
+ // table is built on the FontMgr directly; instead, because we already have
+ // font resources, this code just grabs a font out of GfxCache.
+ if (fontId != _fontId) {
+ _fontId = fontId == -1 ? _defaultFontId : fontId;
+ _font = _cache->getFont(_fontId);
+ }
}
-void GfxText32::drawFrame(const Common::Rect &rect, const int size, const uint8 color, const bool doScaling) {
+void GfxText32::drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling) {
Common::Rect targetRect = doScaling ? scaleRect(rect) : rect;
byte *bitmap = _segMan->getHunkPointer(_bitmap);
- byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28);
+ byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28) + rect.top * _width + rect.left;
// NOTE: Not fully disassembled, but this should be right
- // TODO: Implement variable frame size
- assert(size == 1);
- Buffer buffer(_width, _height, pixels);
- buffer.frameRect(targetRect, color);
+ int16 rectWidth = targetRect.width();
+ int16 sidesHeight = targetRect.height() - size * 2;
+ int16 centerWidth = rectWidth - size * 2;
+ int16 stride = _width - rectWidth;
+
+ for (int16 y = 0; y < size; ++y) {
+ memset(pixels, color, rectWidth);
+ pixels += _width;
+ }
+ for (int16 y = 0; y < sidesHeight; ++y) {
+ for (int16 x = 0; x < size; ++x) {
+ *pixels++ = color;
+ }
+ pixels += centerWidth;
+ for (int16 x = 0; x < size; ++x) {
+ *pixels++ = color;
+ }
+ pixels += stride;
+ }
+ for (int16 y = 0; y < size; ++y) {
+ memset(pixels, color, rectWidth);
+ pixels += _width;
+ }
+}
+
+void GfxText32::drawChar(const char charIndex) {
+ byte *bitmap = _segMan->getHunkPointer(_bitmap);
+ byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28);
+
+ _font->drawToBuffer(charIndex, _drawPosition.y, _drawPosition.x, _foreColor, _dimmed, pixels, _width, _height);
+ _drawPosition.x += _font->getCharWidth(charIndex);
+}
+
+uint16 GfxText32::getCharWidth(const char charIndex, const bool doScaling) const {
+ uint16 width = _font->getCharWidth(charIndex);
+ if (doScaling) {
+ width = scaleUpWidth(width);
+ }
+ return width;
}
-// TODO: This is not disassembled
void GfxText32::drawTextBox() {
- int16 charCount = 0;
- uint16 curX = 0, curY = 0;
- const char *txt = _text.c_str();
- int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0;
- uint16 start = 0;
-
- // Calculate total text height
- while (*txt) {
- charCount = GetLongest(txt, _textRect.width(), _font);
- if (charCount == 0)
- break;
-
- Width(txt, 0, (int16)strlen(txt), _fontId, textWidth, textHeight, true);
-
- totalHeight += textHeight;
- txt += charCount;
- while (*txt == ' ') {
- txt++; // skip over breaking spaces
- }
+ if (_text.size() == 0) {
+ return;
}
- txt = _text.c_str();
-
- byte *pixels = _segMan->getHunkPointer(_bitmap);
- pixels = pixels + READ_SCI11ENDIAN_UINT32(pixels + 28) + _width * _textRect.top + _textRect.left;
-
- // Draw text in buffer
- while (*txt) {
- charCount = GetLongest(txt, _textRect.width(), _font);
- if (charCount == 0)
- break;
- Width(txt, start, charCount, _fontId, textWidth, textHeight, true);
-
- switch (_alignment) {
- case kTextAlignRight:
- offsetX = _textRect.width() - textWidth;
- break;
- case kTextAlignCenter:
- // Center text both horizontally and vertically
- offsetX = (_textRect.width() - textWidth) / 2;
- offsetY = (_textRect.height() - totalHeight) / 2;
- break;
- case kTextAlignLeft:
- offsetX = 0;
- break;
-
- default:
- warning("Invalid alignment %d used in TextBox()", _alignment);
- }
+ const char *text = _text.c_str();
+ const char *sourceText = text;
+ int16 textRectWidth = _textRect.width();
+ _drawPosition.y = _textRect.top;
+ uint charIndex = 0;
- byte curChar;
-
- for (int i = 0; i < charCount; i++) {
- curChar = txt[i];
-
- switch (curChar) {
- case 0x0A:
- case 0x0D:
- case 0:
- break;
- case 0x7C:
- warning("Code processing isn't implemented in SCI32");
- break;
- default:
- _font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, _foreColor, _dimmed, pixels, _width, _height);
- curX += _font->getCharWidth(curChar);
- break;
- }
+ if (g_sci->getGameId() == GID_SQ6 || g_sci->getGameId() == GID_MOTHERGOOSEHIRES) {
+ if (getLongest(&charIndex, textRectWidth) == 0) {
+ error("DrawTextBox GetLongest=0");
}
+ }
+
+ charIndex = 0;
+ uint nextCharIndex = 0;
+ while (*text != '\0') {
+ _drawPosition.x = _textRect.left;
+
+ uint length = getLongest(&nextCharIndex, textRectWidth);
+ int16 textWidth = getTextWidth(charIndex, length);
- curX = 0;
- curY += _font->getHeight();
- txt += charCount;
- while (*txt == ' ') {
- txt++; // skip over breaking spaces
+ if (_alignment == kTextAlignCenter) {
+ _drawPosition.x += (textRectWidth - textWidth) / 2;
+ } else if (_alignment == kTextAlignRight) {
+ _drawPosition.x += textRectWidth - textWidth;
}
+
+ drawText(charIndex, length);
+ charIndex = nextCharIndex;
+ text = sourceText + charIndex;
+ _drawPosition.y += _font->getHeight();
}
}
-void GfxText32::erase(const Common::Rect &rect, const bool doScaling) {
- Common::Rect targetRect = doScaling ? rect : scaleRect(rect);
+void GfxText32::drawTextBox(const Common::String &text) {
+ _text = text;
+ drawTextBox();
+}
- byte *bitmap = _segMan->getHunkPointer(_bitmap);
- byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28);
+void GfxText32::drawText(const uint index, uint length) {
+ assert(index + length <= _text.size());
- // NOTE: There is an extra optimisation within the SCI code to
- // do a single memset if the scaledRect is the same size as
- // the bitmap, not implemented here.
- Buffer buffer(_width, _height, pixels);
- buffer.fillRect(targetRect, _backColor);
-}
+ // NOTE: This draw loop implementation is somewhat different than the
+ // implementation in the actual engine, but should be accurate. Primarily
+ // the changes revolve around eliminating some extra temporaries and
+ // fixing the logic to match.
+ const char *text = _text.c_str() + index;
+ while (length-- > 0) {
+ char currentChar = *text++;
-reg_t GfxText32::createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
- return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk);
-}
-reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
- reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text));
- // The object in the text selector of the item can be either a raw string
- // or a Str object. In the latter case, we need to access the object's data
- // selector to get the raw string.
- if (_segMan->isHeapObject(stringObject))
- stringObject = readSelector(_segMan, stringObject, SELECTOR(data));
+ if (currentChar == '|') {
+ const char controlChar = *text++;
+ --length;
- Common::String text = _segMan->getString(stringObject);
+ if (length == 0) {
+ return;
+ }
+
+ if (controlChar == 'a' || controlChar == 'c' || controlChar == 'f') {
+ uint16 value = 0;
+
+ while (length > 0) {
+ const char valueChar = *text;
+ if (valueChar < '0' || valueChar > '9') {
+ break;
+ }
+
+ ++text;
+ --length;
+ value = 10 * value + (valueChar - '0');
+ }
+
+ if (length == 0) {
+ return;
+ }
+
+ if (controlChar == 'a') {
+ _alignment = (TextAlign)value;
+ } else if (controlChar == 'c') {
+ _foreColor = value;
+ } else if (controlChar == 'f') {
+ setFont(value);
+ }
+ }
- return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk);
+ while (length > 0 && *text != '|') {
+ ++text;
+ --length;
+ }
+ if (length > 0) {
+ ++text;
+ --length;
+ }
+ } else {
+ drawChar(currentChar);
+ }
+ }
}
-reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
- GuiResourceId fontId = readSelectorValue(_segMan, textObject, SELECTOR(font));
- GfxFont *font = _cache->getFont(fontId);
- bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed));
- int16 alignment = readSelectorValue(_segMan, textObject, SELECTOR(mode));
- uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore));
- uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back));
-
- Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject);
- uint16 width = nsRect.width() + 1;
- uint16 height = nsRect.height() + 1;
-
- // Limit rectangle dimensions, if requested
- if (maxWidth > 0)
- width = maxWidth;
- if (maxHeight > 0)
- height = maxHeight;
-
- // Upscale the coordinates/width if the fonts are already upscaled
- if (_screen->fontIsUpscaled()) {
- width = width * _screen->getDisplayWidth() / _screen->getWidth();
- height = height * _screen->getDisplayHeight() / _screen->getHeight();
+void GfxText32::invertRect(const reg_t bitmap, int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling) {
+ Common::Rect targetRect = rect;
+ if (doScaling) {
+ bitmapStride = bitmapStride * _scaledWidth / g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ targetRect = scaleRect(rect);
}
- int entrySize = width * height + BITMAP_HEADER_SIZE;
- reg_t memoryId = NULL_REG;
- if (prevHunk.isNull()) {
- memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize);
+ byte *bitmapData = _segMan->getHunkPointer(bitmap);
- // Scroll text objects have no bitmap selector!
- ObjVarRef varp;
- if (lookupSelector(_segMan, textObject, SELECTOR(bitmap), &varp, NULL) == kSelectorVariable)
- writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId);
- } else {
- memoryId = prevHunk;
- }
- byte *memoryPtr = _segMan->getHunkPointer(memoryId);
-
- if (prevHunk.isNull())
- memset(memoryPtr, 0, BITMAP_HEADER_SIZE);
-
- byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
- memset(bitmap, backColor, width * height);
-
- // Save totalWidth, totalHeight
- WRITE_SCI11ENDIAN_UINT16(memoryPtr, width);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 2, height);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 4, 0);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 6, 0);
- memoryPtr[8] = 0;
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 10, 0);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 20, BITMAP_HEADER_SIZE);
- WRITE_SCI11ENDIAN_UINT32(memoryPtr + 28, 46);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 36, width);
- WRITE_SCI11ENDIAN_UINT16(memoryPtr + 38, height);
-
- int16 charCount = 0;
- uint16 curX = 0, curY = 0;
- const char *txt = text.c_str();
- int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0;
- uint16 start = 0;
-
- // Calculate total text height
- while (*txt) {
- charCount = GetLongest(txt, width, font);
- if (charCount == 0)
- break;
-
- Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true);
-
- totalHeight += textHeight;
- txt += charCount;
- while (*txt == ' ')
- txt++; // skip over breaking spaces
+ // NOTE: SCI code is super weird here; it seems to be trying to look at the
+ // entire size of the bitmap including the header, instead of just the pixel
+ // data size. We just look at the pixel size. This function generally is an
+ // odd duck since the stride dimension for a bitmap is built in to the bitmap
+ // header, so perhaps it was once an unheadered bitmap format and this
+ // function was never updated to match? Or maybe they exploit the
+ // configurable stride length somewhere else to do stair stepping inverts...
+ uint32 invertSize = targetRect.height() * bitmapStride + targetRect.width();
+ uint32 bitmapSize = READ_SCI11ENDIAN_UINT32(bitmapData + 12);
+
+ if (invertSize >= bitmapSize) {
+ error("InvertRect too big: %u >= %u", invertSize, bitmapSize);
}
- txt = text.c_str();
-
- // Draw text in buffer
- while (*txt) {
- charCount = GetLongest(txt, width, font);
- if (charCount == 0)
- break;
- Width(txt, start, charCount, fontId, textWidth, textHeight, true);
-
- switch (alignment) {
- case kTextAlignRight:
- offsetX = width - textWidth;
- break;
- case kTextAlignCenter:
- // Center text both horizontally and vertically
- offsetX = (width - textWidth) / 2;
- offsetY = (height - totalHeight) / 2;
- break;
- case kTextAlignLeft:
- offsetX = 0;
- break;
-
- default:
- warning("Invalid alignment %d used in TextBox()", alignment);
- }
+ // NOTE: Actual engine just added the bitmap header size hardcoded here
+ byte *pixel = bitmapData + READ_SCI11ENDIAN_UINT32(bitmapData + 28) + bitmapStride * targetRect.top + targetRect.left;
- byte curChar;
-
- for (int i = 0; i < charCount; i++) {
- curChar = txt[i];
-
- switch (curChar) {
- case 0x0A:
- case 0x0D:
- case 0:
- break;
- case 0x7C:
- warning("Code processing isn't implemented in SCI32");
- break;
- default:
- font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height);
- curX += font->getCharWidth(curChar);
- break;
+ int16 stride = bitmapStride - targetRect.width();
+ int16 targetHeight = targetRect.height();
+ int16 targetWidth = targetRect.width();
+
+ for (int16 y = 0; y < targetHeight; ++y) {
+ for (int16 x = 0; x < targetWidth; ++x) {
+ if (*pixel == foreColor) {
+ *pixel = backColor;
+ } else if (*pixel == backColor) {
+ *pixel = foreColor;
}
+
+ ++pixel;
}
- curX = 0;
- curY += font->getHeight();
- txt += charCount;
- while (*txt == ' ')
- txt++; // skip over breaking spaces
+ pixel += stride;
}
-
- return memoryId;
}
-void GfxText32::disposeTextBitmap(reg_t hunkId) {
- _segMan->freeHunkEntry(hunkId);
-}
+uint GfxText32::getLongest(uint *charIndex, const int16 width) {
+ assert(width > 0);
-void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject) {
- reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap));
- drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);
-}
+ uint testLength = 0;
+ uint length = 0;
-void GfxText32::drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y) {
- /*reg_t plane = readSelector(_segMan, textObject, SELECTOR(plane));
- Common::Rect planeRect;
- planeRect.top = readSelectorValue(_segMan, plane, SELECTOR(top));
- planeRect.left = readSelectorValue(_segMan, plane, SELECTOR(left));
- planeRect.bottom = readSelectorValue(_segMan, plane, SELECTOR(bottom));
- planeRect.right = readSelectorValue(_segMan, plane, SELECTOR(right));
+ const uint initialCharIndex = *charIndex;
- drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);*/
+ // The index of the next word after the last word break
+ uint lastWordBreakIndex = *charIndex;
- // HACK: we pretty much ignore the plane rect and x, y...
- drawTextBitmapInternal(0, 0, Common::Rect(20, 390, 600, 460), textObject, hunkId);
-}
+ const char *text = _text.c_str() + *charIndex;
-void GfxText32::drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId) {
- int16 backColor = (int16)readSelectorValue(_segMan, textObject, SELECTOR(back));
- // Sanity check: Check if the hunk is set. If not, either the game scripts
- // didn't set it, or an old saved game has been loaded, where it wasn't set.
- if (hunkId.isNull())
- return;
+ char currentChar;
+ while ((currentChar = *text++) != '\0') {
+ // NOTE: In the original engine, the font, color, and alignment were
+ // reset here to their initial values
- // Negative coordinates indicate that text shouldn't be displayed
- if (x < 0 || y < 0)
- return;
+ // The text to render contains a line break; stop at the line break
+ if (currentChar == '\r' || currentChar == '\n') {
+ // Skip the rest of the line break if it is a Windows-style
+ // \r\n or non-standard \n\r
+ // NOTE: In the original engine, the `text` pointer had not been
+ // advanced yet so the indexes used to access characters were
+ // one higher
+ if (
+ (currentChar == '\r' && text[0] == '\n') ||
+ (currentChar == '\n' && text[0] == '\r' && text[1] != '\n')
+ ) {
+ ++*charIndex;
+ }
- byte *memoryPtr = _segMan->getHunkPointer(hunkId);
+ // We are at the end of a line but the last word in the line made
+ // it too wide to fit in the text area; return up to the previous
+ // word
+ if (length && getTextWidth(initialCharIndex, testLength) > width) {
+ *charIndex = lastWordBreakIndex;
+ return length;
+ }
- if (!memoryPtr) {
- // Happens when restoring in some SCI32 games (e.g. SQ6).
- // Commented out to reduce console spam
- //warning("Attempt to draw an invalid text bitmap");
- return;
- }
+ // Skip the line break and return all text seen up to now
+ // NOTE: In original engine, the font, color, and alignment were
+ // reset, then getTextWidth was called to use its side-effects to
+ // set font, color, and alignment according to the text from
+ // `initialCharIndex` to `testLength`
+ ++*charIndex;
+ return testLength;
+ } else if (currentChar == ' ') {
+ // The last word in the line made it too wide to fit in the text area;
+ // return up to the previous word, then collapse the whitespace
+ // between that word and its next sibling word into the line break
+ if (getTextWidth(initialCharIndex, testLength) > width) {
+ *charIndex = lastWordBreakIndex;
+ const char *nextChar = _text.c_str() + lastWordBreakIndex;
+ while (*nextChar++ == ' ') {
+ ++*charIndex;
+ }
+
+ // NOTE: In original engine, the font, color, and alignment were
+ // set here to the values that were seen at the last space character
+ return length;
+ }
- byte *surface = memoryPtr + BITMAP_HEADER_SIZE;
+ // NOTE: In the original engine, the values of _fontId, _foreColor,
+ // and _alignment were stored for use in the return path mentioned
+ // just above here
- int curByte = 0;
- int16 skipColor = (int16)readSelectorValue(_segMan, textObject, SELECTOR(skip));
- uint16 textX = planeRect.left + x;
- uint16 textY = planeRect.top + y;
- // Get totalWidth, totalHeight
- uint16 width = READ_LE_UINT16(memoryPtr);
- uint16 height = READ_LE_UINT16(memoryPtr + 2);
+ // We found a word break that was within the text area, memorise it
+ // and continue processing. +1 on the character index because it has
+ // not been incremented yet so currently points to the word break
+ // and not the word after the break
+ length = testLength;
+ lastWordBreakIndex = *charIndex + 1;
+ }
- // Upscale the coordinates/width if the fonts are already upscaled
- if (_screen->fontIsUpscaled()) {
- textX = textX * _screen->getDisplayWidth() / _screen->getWidth();
- textY = textY * _screen->getDisplayHeight() / _screen->getHeight();
- }
+ // In the middle of a line, keep processing
+ ++*charIndex;
+ ++testLength;
- bool translucent = (skipColor == -1 && backColor == -1);
+ // NOTE: In the original engine, the font, color, and alignment were
+ // reset here to their initial values
- for (int curY = 0; curY < height; curY++) {
- for (int curX = 0; curX < width; curX++) {
- byte pixel = surface[curByte++];
- if ((!translucent && pixel != skipColor && pixel != backColor) ||
- (translucent && pixel != 0xFF))
- _screen->putFontPixel(textY, curX + textX, curY, pixel);
+ // The text to render contained no word breaks yet but is already too
+ // wide for the text area; just split the word in half at the point
+ // where it overflows
+ if (length == 0 && getTextWidth(initialCharIndex, testLength) > width) {
+ *charIndex = --testLength + lastWordBreakIndex;
+ return testLength;
}
}
+
+ // The complete text to render was a single word, or was narrower than
+ // the text area, so return the entire line
+ if (length == 0 || getTextWidth(initialCharIndex, testLength) <= width) {
+ // NOTE: In original engine, the font, color, and alignment were
+ // reset, then getTextWidth was called to use its side-effects to
+ // set font, color, and alignment according to the text from
+ // `initialCharIndex` to `testLength`
+ return testLength;
+ }
+
+ // The last word in the line made it wider than the text area, so return
+ // up to the penultimate word
+ *charIndex = lastWordBreakIndex;
+ return length;
}
-int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) {
- uint16 curChar = 0;
- int16 maxChars = 0, curCharCount = 0;
- uint16 width = 0;
-
- while (width <= maxWidth) {
- curChar = (*(const byte *)text++);
-
- switch (curChar) {
- // We need to add 0xD, 0xA and 0xD 0xA to curCharCount and then exit
- // which means, we split text like
- // 'Mature, experienced software analyst available.' 0xD 0xA
- // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2)
- // and 0xA '-------' 0xA (which is the official sierra subtitle separator)
- // Sierra did it the same way.
- case 0xD:
- // Check, if 0xA is following, if so include it as well
- if ((*(const unsigned char *)text) == 0xA)
- curCharCount++;
- // it's meant to pass through here
- case 0xA:
- curCharCount++;
- // and it's also meant to pass through here
- case 0:
- return curCharCount;
- case ' ':
- maxChars = curCharCount; // return count up to (but not including) breaking space
- break;
+int16 GfxText32::getTextWidth(const uint index, uint length) const {
+ int16 width = 0;
+
+ const char *text = _text.c_str() + index;
+
+ GfxFont *font = _font;
+
+ char currentChar = *text++;
+ while (length > 0 && currentChar != '\0') {
+ // Control codes are in the format `|<code><value>|`
+ if (currentChar == '|') {
+ // NOTE: Original engine code changed the global state of the
+ // FontMgr here upon encountering any color, alignment, or
+ // font control code.
+ // To avoid requiring all callers to manually restore these
+ // values on every call, we ignore control codes other than
+ // font change (since alignment and color do not change the
+ // width of characters), and simply update the font pointer
+ // on stack instead of the member property font.
+ currentChar = *text++;
+ --length;
+
+ if (length > 0 && currentChar == 'f') {
+ GuiResourceId fontId = 0;
+ do {
+ currentChar = *text++;
+ --length;
+
+ fontId = fontId * 10 + currentChar - '0';
+ } while (length > 0 && *text >= '0' && *text <= '9');
+
+ if (length > 0) {
+ font = _cache->getFont(fontId);
+ }
+ }
+
+ // Forward through any more unknown control character data
+ while (length > 0 && *text != '|') {
+ ++text;
+ --length;
+ }
+ if (length > 0) {
+ ++text;
+ --length;
+ }
+ } else {
+ width += font->getCharWidth(currentChar);
+ }
+
+ if (length > 0) {
+ currentChar = *text++;
+ --length;
}
- if (width + font->getCharWidth(curChar) > maxWidth)
- break;
- width += font->getCharWidth(curChar);
- curCharCount++;
}
- return maxChars;
+ return width;
}
-void GfxText32::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) {
- Common::Rect rect(0, 0, 0, 0);
- Size(rect, text, font, maxWidth);
- *textWidth = rect.width();
- *textHeight = rect.height();
+int16 GfxText32::getTextWidth(const Common::String &text, const uint index, const uint length) {
+ _text = text;
+ return scaleUpWidth(getTextWidth(index, length));
}
-void GfxText32::StringWidth(const char *str, GuiResourceId fontId, int16 &textWidth, int16 &textHeight) {
- Width(str, 0, (int16)strlen(str), fontId, textWidth, textHeight, true);
-}
+Common::Rect GfxText32::getTextSize(const Common::String &text, int16 maxWidth, bool doScaling) {
+ // NOTE: Like most of the text rendering code, this function was pretty
+ // weird in the original engine. The initial result rectangle was actually
+ // a 1x1 rectangle (0, 0, 0, 0), which was then "fixed" after the main
+ // text size loop finished running by subtracting 1 from the right and
+ // bottom edges. Like other functions in SCI32, this has been converted
+ // to use exclusive rects with inclusive rounding.
+
+ Common::Rect result;
+
+ int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
-void GfxText32::Width(const char *text, int16 from, int16 len, GuiResourceId fontId, int16 &textWidth, int16 &textHeight, bool restoreFont) {
- byte curChar;
- textWidth = 0; textHeight = 0;
-
- GfxFont *font = _cache->getFont(fontId);
-
- if (font) {
- text += from;
- while (len--) {
- curChar = (*(const byte *)text++);
- switch (curChar) {
- case 0x0A:
- case 0x0D:
- textHeight = MAX<int16> (textHeight, font->getHeight());
- break;
- case 0x7C:
- warning("Code processing isn't implemented in SCI32");
- break;
- default:
- textHeight = MAX<int16> (textHeight, font->getHeight());
- textWidth += font->getCharWidth(curChar);
- break;
+ maxWidth = maxWidth * _scaledWidth / scriptWidth;
+
+ _text = text;
+
+ if (maxWidth >= 0) {
+ if (maxWidth == 0) {
+ maxWidth = _scaledWidth * 3 / 5;
+ }
+
+ result.right = maxWidth;
+
+ int16 textWidth = 0;
+ if (_text.size() > 0) {
+ const char *rawText = _text.c_str();
+ const char *sourceText = rawText;
+ uint charIndex = 0;
+ uint nextCharIndex = 0;
+ while (*rawText != '\0') {
+ uint length = getLongest(&nextCharIndex, result.width());
+ textWidth = MAX(textWidth, getTextWidth(charIndex, length));
+ charIndex = nextCharIndex;
+ rawText = sourceText + charIndex;
+ // TODO: Due to getLongest and getTextWidth not having side
+ // effects, it is possible that the currently loaded font's
+ // height is wrong for this line if it was changed inline
+ result.bottom += _font->getHeight();
}
}
+
+ if (textWidth < maxWidth) {
+ result.right = textWidth;
+ }
+ } else {
+ result.right = getTextWidth(0, 10000);
+
+ if (getSciVersion() < SCI_VERSION_2_1_MIDDLE) {
+ result.bottom = 0;
+ } else {
+ // NOTE: In the original engine code, the bottom was not decremented
+ // by 1, which means that the rect was actually a pixel taller than
+ // the height of the font. This was not the case in the other branch,
+ // which decremented the bottom by 1 at the end of the loop.
+ result.bottom = _font->getHeight() + 1;
+ }
}
+
+ if (doScaling) {
+ // NOTE: The original engine code also scaled top/left but these are
+ // always zero so there is no reason to do that.
+ result.right = ((result.right - 1) * scriptWidth + _scaledWidth - 1) / _scaledWidth + 1;
+ result.bottom = ((result.bottom - 1) * scriptHeight + _scaledHeight - 1) / _scaledHeight + 1;
+ }
+
+ return result;
+}
+
+void GfxText32::erase(const Common::Rect &rect, const bool doScaling) {
+ Common::Rect targetRect = doScaling ? scaleRect(rect) : rect;
+
+ BitmapResource bitmap(_bitmap);
+ bitmap.getBuffer().fillRect(targetRect, _backColor);
}
-int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) {
- int16 charCount;
- int16 maxTextWidth = 0, textWidth;
- int16 totalHeight = 0, textHeight;
+int16 GfxText32::getStringWidth(const Common::String &text) {
+ return getTextWidth(text, 0, 10000);
+}
- int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
- int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+int16 GfxText32::getTextCount(const Common::String &text, const uint index, const Common::Rect &textRect, const bool doScaling) {
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
- maxWidth = maxWidth * _scaledWidth / scriptWidth;
+ Common::Rect scaledRect(textRect);
+ if (doScaling) {
+ mulinc(scaledRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight));
+ }
- rect.top = rect.left = 0;
- GfxFont *font = _cache->getFont(fontId);
+ Common::String oldText = _text;
+ _text = text;
- if (maxWidth < 0) { // force output as single line
- StringWidth(text, fontId, textWidth, textHeight);
- rect.bottom = textHeight;
- rect.right = textWidth;
+ uint charIndex = index;
+ int16 maxWidth = scaledRect.width();
+ int16 lineCount = (scaledRect.height() - 2) / _font->getHeight();
+ while (lineCount--) {
+ getLongest(&charIndex, maxWidth);
+ }
+
+ _text = oldText;
+ return charIndex - index;
+}
+
+int16 GfxText32::getTextCount(const Common::String &text, const uint index, const GuiResourceId fontId, const Common::Rect &textRect, const bool doScaling) {
+ setFont(fontId);
+ return getTextCount(text, index, textRect, doScaling);
+}
+
+void GfxText32::scrollLine(const Common::String &lineText, int numLines, uint8 color, TextAlign align, GuiResourceId fontId, ScrollDirection dir) {
+ BitmapResource bmr(_bitmap);
+ byte *pixels = bmr.getPixels();
+
+ int h = _font->getHeight();
+
+ if (dir == kScrollUp) {
+ // Scroll existing text down
+ for (int i = 0; i < (numLines - 1) * h; ++i) {
+ int y = _textRect.top + numLines * h - i - 1;
+ memcpy(pixels + y * _width + _textRect.left,
+ pixels + (y - h) * _width + _textRect.left,
+ _textRect.width());
+ }
} else {
- // rect.right=found widest line with RTextWidth and GetLongest
- // rect.bottom=num. lines * GetPointSize
- rect.right = (maxWidth ? maxWidth : 192);
- const char *curPos = text;
- while (*curPos) {
- charCount = GetLongest(curPos, rect.right, font);
- if (charCount == 0)
- break;
- Width(curPos, 0, charCount, fontId, textWidth, textHeight, false);
- maxTextWidth = MAX(textWidth, maxTextWidth);
- totalHeight += textHeight;
- curPos += charCount;
- while (*curPos == ' ')
- curPos++; // skip over breaking spaces
+ // Scroll existing text up
+ for (int i = 0; i < (numLines - 1) * h; ++i) {
+ int y = _textRect.top + i;
+ memcpy(pixels + y * _width + _textRect.left,
+ pixels + (y + h) * _width + _textRect.left,
+ _textRect.width());
}
- rect.bottom = totalHeight;
- rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth);
}
- rect.right = rect.right * scriptWidth / _scaledWidth;
- rect.bottom = rect.bottom * scriptHeight / _scaledHeight;
+ Common::Rect lineRect = _textRect;
+
+ if (dir == kScrollUp) {
+ lineRect.bottom = lineRect.top + h;
+ } else {
+ // It is unclear to me what the purpose of this bottom++ is.
+ // It does not seem to be the usual inc/exc issue.
+ lineRect.top += (numLines - 1) * h;
+ lineRect.bottom++;
+ }
- return rect.right;
+ erase(lineRect, false);
+
+ _drawPosition.x = _textRect.left;
+ _drawPosition.y = _textRect.top;
+ if (dir == kScrollDown) {
+ _drawPosition.y += (numLines - 1) * h;
+ }
+
+ _foreColor = color;
+ _alignment = align;
+ //int fc = _foreColor;
+
+ setFont(fontId);
+
+ _text = lineText;
+ int16 textWidth = getTextWidth(0, lineText.size());
+
+ if (_alignment == kTextAlignCenter) {
+ _drawPosition.x += (_textRect.width() - textWidth) / 2;
+ } else if (_alignment == kTextAlignRight) {
+ _drawPosition.x += _textRect.width() - textWidth;
+ }
+
+ //_foreColor = fc;
+ //setFont(fontId);
+
+ drawText(0, lineText.size());
}
+
} // End of namespace Sci
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 08568e4958..a61760dd87 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -23,17 +23,227 @@
#ifndef SCI_GRAPHICS_TEXT32_H
#define SCI_GRAPHICS_TEXT32_H
+#include "sci/engine/state.h"
#include "sci/graphics/celobj32.h"
#include "sci/graphics/frameout.h"
+#include "sci/graphics/helpers.h"
namespace Sci {
enum TextAlign {
- kTextAlignLeft = 0,
- kTextAlignCenter = 1,
- kTextAlignRight = -1
+ kTextAlignDefault = -1,
+ kTextAlignLeft = 0,
+ kTextAlignCenter = 1,
+ kTextAlignRight = 2
};
+enum ScrollDirection {
+ kScrollUp,
+ kScrollDown
+};
+
+enum BitmapFlags {
+ kBitmapRemap = 2
+};
+
+#define BITMAP_PROPERTY(size, property, offset)\
+inline uint##size get##property() const {\
+ return READ_SCI11ENDIAN_UINT##size(_bitmap + (offset));\
+}\
+inline void set##property(uint##size value) {\
+ WRITE_SCI11ENDIAN_UINT##size(_bitmap + (offset), (value));\
+}
+
+/**
+ * A convenience class for creating and modifying in-memory
+ * bitmaps.
+ */
+class BitmapResource {
+ byte *_bitmap;
+ reg_t _object;
+ Buffer _buffer;
+
+ /**
+ * Gets the size of the bitmap header for the current
+ * engine version.
+ */
+ static inline uint16 getBitmapHeaderSize() {
+ // TODO: These values are accurate for each engine, but there may be no reason
+ // to not simply just always use size 40, since SCI2.1mid does not seem to
+ // actually store any data above byte 40, and SCI2 did not allow bitmaps with
+ // scaling resolutions other than the default (320x200). Perhaps SCI3 used
+ // the extra bytes, or there is some reason why they tried to align the header
+ // size with other headers like pic headers?
+// uint32 bitmapHeaderSize;
+// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
+// bitmapHeaderSize = 46;
+// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
+// bitmapHeaderSize = 40;
+// } else {
+// bitmapHeaderSize = 36;
+// }
+// return bitmapHeaderSize;
+ return 46;
+ }
+
+ /**
+ * Gets the byte size of a bitmap with the given width
+ * and height.
+ */
+ static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
+ return width * height + getBitmapHeaderSize();
+ }
+
+public:
+ /**
+ * Create a bitmap resource for an existing bitmap.
+ * Ownership of the bitmap is retained by the caller.
+ */
+ inline BitmapResource(reg_t bitmap) :
+ _bitmap(g_sci->getEngineState()->_segMan->getHunkPointer(bitmap)),
+ _object(bitmap) {
+ if (_bitmap == nullptr || getUncompressedDataOffset() != getBitmapHeaderSize()) {
+ error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap));
+ }
+
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
+
+ /**
+ * Allocates and initialises a new bitmap in the given
+ * segment manager.
+ */
+ inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool remap) {
+ _object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height));
+ _bitmap = segMan->getHunkPointer(_object);
+
+ const uint16 bitmapHeaderSize = getBitmapHeaderSize();
+
+ setWidth(width);
+ setHeight(height);
+ setDisplace(Common::Point(displaceX, displaceY));
+ setSkipColor(skipColor);
+ _bitmap[9] = 0;
+ WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, 0);
+ setRemap(remap);
+ setDataSize(width * height);
+ WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0);
+ setHunkPaletteOffset(hunkPaletteOffset);
+ setDataOffset(bitmapHeaderSize);
+ setUncompressedDataOffset(bitmapHeaderSize);
+ setControlOffset(0);
+ setScaledWidth(scaledWidth);
+ setScaledHeight(scaledHeight);
+
+ _buffer = Buffer(getWidth(), getHeight(), getPixels());
+ }
+
+ inline reg_t getObject() const {
+ return _object;
+ }
+
+ inline Buffer &getBuffer() {
+ return _buffer;
+ }
+
+ BITMAP_PROPERTY(16, Width, 0);
+ BITMAP_PROPERTY(16, Height, 2);
+
+ inline Common::Point getDisplace() const {
+ return Common::Point(
+ (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 4),
+ (int16)READ_SCI11ENDIAN_UINT16(_bitmap + 6)
+ );
+ }
+
+ inline void setDisplace(const Common::Point &displace) {
+ WRITE_SCI11ENDIAN_UINT16(_bitmap + 4, (uint16)displace.x);
+ WRITE_SCI11ENDIAN_UINT16(_bitmap + 6, (uint16)displace.y);
+ }
+
+ inline uint8 getSkipColor() const {
+ return _bitmap[8];
+ }
+
+ inline void setSkipColor(const uint8 skipColor) {
+ _bitmap[8] = skipColor;
+ }
+
+ inline bool getRemap() const {
+ return READ_SCI11ENDIAN_UINT16(_bitmap + 10) & kBitmapRemap;
+ }
+
+ inline void setRemap(const bool remap) {
+ uint16 flags = READ_SCI11ENDIAN_UINT16(_bitmap + 10);
+ if (remap) {
+ flags |= kBitmapRemap;
+ } else {
+ flags &= ~kBitmapRemap;
+ }
+ WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, flags);
+ }
+
+ BITMAP_PROPERTY(32, DataSize, 12);
+
+ inline uint32 getHunkPaletteOffset() const {
+ return READ_SCI11ENDIAN_UINT32(_bitmap + 20);
+ }
+
+ inline void setHunkPaletteOffset(uint32 hunkPaletteOffset) {
+ if (hunkPaletteOffset) {
+ hunkPaletteOffset += getBitmapHeaderSize();
+ }
+
+ WRITE_SCI11ENDIAN_UINT32(_bitmap + 20, hunkPaletteOffset);
+ }
+
+ BITMAP_PROPERTY(32, DataOffset, 24);
+
+ // NOTE: This property is used as a "magic number" for
+ // validating that a block of memory is a valid bitmap,
+ // and so is always set to the size of the header.
+ BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
+
+ // NOTE: This property always seems to be zero
+ BITMAP_PROPERTY(32, ControlOffset, 32);
+
+ inline uint16 getScaledWidth() const {
+ if (getDataOffset() >= 40) {
+ return READ_SCI11ENDIAN_UINT16(_bitmap + 36);
+ }
+
+ // SCI2 bitmaps did not have scaling ability
+ return 320;
+ }
+
+ inline void setScaledWidth(uint16 scaledWidth) {
+ if (getDataOffset() >= 40) {
+ WRITE_SCI11ENDIAN_UINT16(_bitmap + 36, scaledWidth);
+ }
+ }
+
+ inline uint16 getScaledHeight() const {
+ if (getDataOffset() >= 40) {
+ return READ_SCI11ENDIAN_UINT16(_bitmap + 38);
+ }
+
+ // SCI2 bitmaps did not have scaling ability
+ return 200;
+ }
+
+ inline void setScaledHeight(uint16 scaledHeight) {
+ if (getDataOffset() >= 40) {
+ WRITE_SCI11ENDIAN_UINT16(_bitmap + 38, scaledHeight);
+ }
+ }
+
+ inline byte *getPixels() {
+ return _bitmap + getUncompressedDataOffset();
+ }
+};
+
+class GfxFont;
+
/**
* This class handles text calculation and rendering for
* SCI32 games. The text calculation system in SCI32 is
@@ -43,6 +253,9 @@ enum TextAlign {
*/
class GfxText32 {
private:
+ SegManager *_segMan;
+ GfxCache *_cache;
+
/**
* The resource ID of the default font used by the game.
*
@@ -54,6 +267,8 @@ private:
/**
* The width and height of the currently active text
* bitmap, in text-system coordinates.
+ *
+ * @note These are unsigned in the actual engine.
*/
int16 _width, _height;
@@ -106,32 +321,31 @@ private:
TextAlign _alignment;
/**
- * The memory handle of the currently active bitmap.
+ * The position of the text draw cursor.
*/
- reg_t _bitmap;
+ Common::Point _drawPosition;
+
+ void drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling);
+
+ void drawChar(const char charIndex);
+ void drawText(const uint index, uint length);
/**
- * TODO: Document
+ * Gets the length of the longest run of text available
+ * within the currently loaded text, starting from the
+ * given `charIndex` and running for up to `maxWidth`
+ * pixels. Returns the number of characters that can be
+ * written, and mutates the value pointed to by
+ * `charIndex` to point to the index of the next
+ * character to render.
*/
- int _field_22;
+ uint getLongest(uint *charIndex, const int16 maxWidth);
/**
- * The currently active font resource used to write text
- * into the bitmap.
- *
- * @note SCI engine builds the font table directly
- * inside of FontMgr; we use GfxFont instead.
+ * Gets the pixel width of a substring of the currently
+ * loaded text, without scaling.
*/
- GfxFont *_font;
-
- // TODO: This is general for all CelObjMem and should be
- // put in a single location, like maybe as a static
- // method of CelObjMem?!
- void buildBitmapHeader(byte *bitmap, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool useRemap) const;
-
- void drawFrame(const Common::Rect &rect, const int size, const uint8 color, const bool doScaling);
- void drawTextBox();
- void erase(const Common::Rect &rect, const bool doScaling);
+ int16 getTextWidth(const uint index, uint length) const;
inline Common::Rect scaleRect(const Common::Rect &rect) {
Common::Rect scaledRect(rect);
@@ -139,51 +353,132 @@ private:
int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
Ratio scaleX(_scaledWidth, scriptWidth);
Ratio scaleY(_scaledHeight, scriptHeight);
- mul(scaledRect, scaleX, scaleY);
+ mulinc(scaledRect, scaleX, scaleY);
return scaledRect;
}
public:
- GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen);
+ GfxText32(SegManager *segMan, GfxCache *fonts);
+
+ /**
+ * The memory handle of the currently active bitmap.
+ */
+ reg_t _bitmap;
/**
* The size of the x-dimension of the coordinate system
- * used by the text renderer.
+ * used by the text renderer. Static since it was global in SSCI.
*/
- int16 _scaledWidth;
+ static int16 _scaledWidth;
/**
* The size of the y-dimension of the coordinate system
- * used by the text renderer.
+ * used by the text renderer. Static since it was global in SSCI.
*/
- int16 _scaledHeight;
+ static int16 _scaledHeight;
- reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling, reg_t *outBitmapObject);
+ /**
+ * The currently active font resource used to write text
+ * into the bitmap.
+ *
+ * @note SCI engine builds the font table directly
+ * inside of FontMgr; we use GfxFont instead.
+ */
+ GfxFont *_font;
- reg_t createTitledFontBitmap(CelInfo32 &celInfo, Common::Rect &rect, Common::String &text, int16 foreColor, int16 backColor, int font, int16 skipColor, int16 borderColor, bool dimmed, void *unknown1);
+ /**
+ * Creates a plain font bitmap with a flat color
+ * background.
+ */
+ reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling);
-#pragma mark -
-#pragma mark Old stuff
+ /**
+ * Creates a font bitmap with a view background.
+ */
+ reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed);
- reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG);
- reg_t createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG);
- void drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject);
- void drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y);
- void disposeTextBitmap(reg_t hunkId);
- int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font);
+ inline int scaleUpWidth(int value) const {
+ const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth;
+ }
- void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
+ inline int scaleUpHeight(int value) const {
+ const int scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+ return (value * scriptHeight + _scaledHeight - 1) / _scaledHeight;
+ }
-private:
- reg_t createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t hunkId);
- void drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId);
- int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth);
- void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont);
- void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight);
+ /**
+ * Draws the text to the bitmap.
+ */
+ void drawTextBox();
- SegManager *_segMan;
- GfxCache *_cache;
- GfxScreen *_screen;
+ /**
+ * Draws the given text to the bitmap.
+ *
+ * @note The original engine holds a reference to a
+ * shared string which lets the text be updated from
+ * outside of the font manager. Instead, we give this
+ * extra signature to send the text to draw.
+ *
+ * TODO: Use shared string instead?
+ */
+ void drawTextBox(const Common::String &text);
+
+ /**
+ * Erases the given rect by filling with the background
+ * color.
+ */
+ void erase(const Common::Rect &rect, const bool doScaling);
+
+ void invertRect(const reg_t bitmap, const int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling);
+
+ /**
+ * Sets the font to be used for rendering and
+ * calculation of text dimensions.
+ */
+ void setFont(const GuiResourceId fontId);
+
+ /**
+ * Gets the width of a character.
+ */
+ uint16 getCharWidth(const char charIndex, const bool doScaling) const;
+
+ /**
+ * Retrieves the width and height of a block of text.
+ */
+ Common::Rect getTextSize(const Common::String &text, const int16 maxWidth, bool doScaling);
+
+ /**
+ * Gets the pixel width of a substring of the currently
+ * loaded text, with scaling.
+ */
+ int16 getTextWidth(const Common::String &text, const uint index, const uint length);
+
+ /**
+ * Retrieves the width of a line of text.
+ */
+ int16 getStringWidth(const Common::String &text);
+
+ /**
+ * Gets the number of characters of `text`, starting
+ * from `index`, that can be safely rendered into
+ * `textRect`.
+ */
+ int16 getTextCount(const Common::String &text, const uint index, const Common::Rect &textRect, const bool doScaling);
+
+ /**
+ * Gets the number of characters of `text`, starting
+ * from `index`, that can be safely rendered into
+ * `textRect` using the given font.
+ */
+ int16 getTextCount(const Common::String &text, const uint index, const GuiResourceId fontId, const Common::Rect &textRect, const bool doScaling);
+
+ /**
+ * Scroll up/down one line. `numLines` is the number of the lines in the
+ * textarea, and `textLine` contains the text to draw as the newly
+ * visible line. Originally FontMgr::DrawOneLine and FontMgr::UpOneLine.
+ */
+ void scrollLine(const Common::String &textLine, int numLines, uint8 color, TextAlign align, GuiResourceId fontId, ScrollDirection dir);
};
} // End of namespace Sci
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
new file mode 100644
index 0000000000..dd841f5b4c
--- /dev/null
+++ b/engines/sci/graphics/video32.cpp
@@ -0,0 +1,415 @@
+/* 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.
+ *
+ */
+
+#include "audio/mixer.h"
+#include "common/config-manager.h"
+#include "sci/console.h"
+#include "sci/event.h"
+#include "sci/graphics/cursor.h"
+#include "sci/graphics/frameout.h"
+#include "sci/graphics/palette32.h"
+#include "sci/graphics/text32.h"
+#include "sci/graphics/video32.h"
+#include "sci/sci.h"
+#include "video/coktel_decoder.h"
+
+namespace Sci {
+
+#pragma mark VMDPlayer
+
+VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
+ _segMan(segMan),
+ _eventMan(eventMan),
+ _decoder(new Video::AdvancedVMDDecoder(Audio::Mixer::kSFXSoundType)),
+
+ _isOpen(false),
+ _isInitialized(false),
+ _yieldInterval(0),
+ _lastYieldedFrameNo(0),
+
+ _plane(nullptr),
+ _screenItem(nullptr),
+ _planeIsOwned(true),
+ _priority(0),
+ _doublePixels(false),
+ _stretchVertical(false),
+ _blackLines(false),
+ _leaveScreenBlack(false),
+ _leaveLastFrame(false),
+
+ _blackoutPlane(nullptr),
+
+ _startColor(0),
+ _endColor(255),
+ _blackPalette(false),
+
+ _boostPercent(100),
+ _boostStartColor(0),
+ _boostEndColor(255),
+
+ _showCursor(false) {}
+
+VMDPlayer::~VMDPlayer() {
+ close();
+ delete _decoder;
+}
+
+#pragma mark -
+#pragma mark VMDPlayer - Playback
+
+VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFlags flags) {
+ if (_isOpen) {
+ error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
+ }
+
+ if (_decoder->loadFile(fileName)) {
+ if (flags & kOpenFlagMute) {
+ _decoder->setVolume(0);
+ }
+ _isOpen = true;
+ return kIOSuccess;
+ } else {
+ return kIOError;
+ }
+}
+
+void VMDPlayer::init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor) {
+ _x = getSciVersion() >= SCI_VERSION_3 ? x : (x & ~1);
+ _y = y;
+ _doublePixels = flags & kPlayFlagDoublePixels;
+ _blackLines = ConfMan.getBool("enable_black_lined_video") && (flags & kPlayFlagBlackLines);
+ _boostPercent = 100 + (flags & kPlayFlagBoost ? boostPercent : 0);
+ _boostStartColor = CLIP<int16>(boostStartColor, 0, 255);
+ _boostEndColor = CLIP<int16>(boostEndColor, 0, 255);
+ _leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
+ _leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
+ _blackPalette = flags & kPlayFlagBlackPalette;
+ _stretchVertical = flags & kPlayFlagStretchVertical;
+}
+
+VMDPlayer::IOStatus VMDPlayer::close() {
+ if (!_isOpen) {
+ return kIOSuccess;
+ }
+
+ _decoder->close();
+ _isOpen = false;
+ _isInitialized = false;
+
+ if (!_planeIsOwned && _screenItem != nullptr) {
+ g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
+ _screenItem = nullptr;
+ } else if (_plane != nullptr) {
+ g_sci->_gfxFrameout->deletePlane(*_plane);
+ _plane = nullptr;
+ }
+
+ if (!_leaveLastFrame && _leaveScreenBlack) {
+ // This call *actually* deletes the plane/screen item
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+
+ if (_blackoutPlane != nullptr) {
+ g_sci->_gfxFrameout->deletePlane(*_blackoutPlane);
+ _blackoutPlane = nullptr;
+ }
+
+ if (!_leaveLastFrame && !_leaveScreenBlack) {
+ // This call *actually* deletes the blackout plane
+ g_sci->_gfxFrameout->frameOut(true);
+ }
+
+ if (!_showCursor) {
+ g_sci->_gfxCursor->kernelShow();
+ }
+
+ _lastYieldedFrameNo = 0;
+ _planeIsOwned = true;
+ _priority = 0;
+ return kIOSuccess;
+}
+
+VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
+ assert(lastFrameNo >= -1);
+
+ const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
+
+ if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
+ _decoder->setEndFrame(MIN((int32)lastFrameNo, maxFrameNo));
+ } else {
+ _decoder->setEndFrame(maxFrameNo);
+ }
+
+ if (flags & kEventFlagYieldToVM) {
+ _yieldInterval = 3;
+ if (yieldInterval == -1 && !(flags & kEventFlagToFrame)) {
+ _yieldInterval = lastFrameNo;
+ } else if (yieldInterval != -1) {
+ _yieldInterval = MIN((int32)yieldInterval, maxFrameNo);
+ }
+ } else {
+ _yieldInterval = maxFrameNo;
+ }
+
+ return playUntilEvent(flags);
+}
+
+VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
+ // Flushing all the keyboard and mouse events out of the event manager to
+ // avoid letting any events queued from before the video started from
+ // accidentally activating an event callback
+ for (;;) {
+ const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_QUIT);
+ if (event.type == SCI_EVENT_NONE) {
+ break;
+ } else if (event.type == SCI_EVENT_QUIT) {
+ return kEventFlagEnd;
+ }
+ }
+
+ _decoder->pauseVideo(false);
+
+ if (flags & kEventFlagReverse) {
+ // NOTE: This flag may not work properly since SSCI does not care
+ // if a video has audio, but the VMD decoder does.
+ const bool success = _decoder->setReverse(true);
+ assert(success);
+ _decoder->setVolume(0);
+ }
+
+ if (!_isInitialized) {
+ _isInitialized = true;
+
+ if (!_showCursor) {
+ g_sci->_gfxCursor->kernelHide();
+ }
+
+ Common::Rect vmdRect(_x,
+ _y,
+ _x + _decoder->getWidth(),
+ _y + _decoder->getHeight());
+ ScaleInfo vmdScaleInfo;
+
+ if (!_blackoutRect.isEmpty() && _planeIsOwned) {
+ _blackoutPlane = new Plane(_blackoutRect);
+ g_sci->_gfxFrameout->addPlane(*_blackoutPlane);
+ }
+
+ if (_doublePixels) {
+ vmdScaleInfo.x = 256;
+ vmdScaleInfo.y = 256;
+ vmdScaleInfo.signal = kScaleSignalDoScaling32;
+ vmdRect.right += vmdRect.width();
+ vmdRect.bottom += vmdRect.height();
+ } else if (_stretchVertical) {
+ vmdScaleInfo.y = 256;
+ vmdScaleInfo.signal = kScaleSignalDoScaling32;
+ vmdRect.bottom += vmdRect.height();
+ }
+
+ const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth;
+ const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight;
+ const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
+ const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
+
+ BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false);
+
+ if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
+ mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
+ }
+
+ CelInfo32 vmdCelInfo;
+ vmdCelInfo.bitmap = vmdBitmap.getObject();
+ _decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
+
+ if (_planeIsOwned) {
+ _x = 0;
+ _y = 0;
+ _plane = new Plane(vmdRect, kPlanePicColored);
+ if (_priority) {
+ _plane->_priority = _priority;
+ }
+ g_sci->_gfxFrameout->addPlane(*_plane);
+ _screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(), vmdScaleInfo);
+ } else {
+ _screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(_x, _y), vmdScaleInfo);
+ if (_priority) {
+ _screenItem->_priority = _priority;
+ }
+ }
+
+ if (_blackLines) {
+ _screenItem->_drawBlackLines = true;
+ }
+
+ // NOTE: There was code for positioning the screen item using insetRect
+ // here, but none of the game scripts seem to use this functionality.
+
+ g_sci->_gfxFrameout->addScreenItem(*_screenItem);
+
+ _decoder->start();
+ }
+
+ EventFlags stopFlag = kEventFlagNone;
+ while (!g_engine->shouldQuit()) {
+ if (_decoder->endOfVideo()) {
+ stopFlag = kEventFlagEnd;
+ break;
+ }
+
+ g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame());
+ g_sci->getEngineState()->_throttleTrigger = true;
+ if (_decoder->needsUpdate()) {
+ renderFrame();
+ }
+
+ const int currentFrameNo = _decoder->getCurFrame();
+
+ if (_yieldInterval > 0 &&
+ currentFrameNo != _lastYieldedFrameNo &&
+ (currentFrameNo % _yieldInterval) == 0
+ ) {
+ _lastYieldedFrameNo = currentFrameNo;
+ stopFlag = kEventFlagYieldToVM;
+ break;
+ }
+
+ SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK);
+ if ((flags & kEventFlagMouseDown) && event.type == SCI_EVENT_MOUSE_PRESS) {
+ stopFlag = kEventFlagMouseDown;
+ break;
+ }
+
+ event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
+ if ((flags & kEventFlagEscapeKey) && event.type == SCI_EVENT_KEYBOARD) {
+ bool stop = false;
+ if (getSciVersion() < SCI_VERSION_3) {
+ while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)),
+ event.type != SCI_EVENT_NONE) {
+ if (event.character == SCI_KEY_ESC) {
+ stop = true;
+ break;
+ }
+ }
+ } else {
+ stop = (event.character == SCI_KEY_ESC);
+ }
+
+ if (stop) {
+ stopFlag = kEventFlagEscapeKey;
+ break;
+ }
+ }
+
+ // TODO: Hot rectangles
+ if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) {
+ warning("Hot rectangles not implemented in VMD player");
+ stopFlag = kEventFlagHotRectangle;
+ break;
+ }
+ }
+
+ _decoder->pauseVideo(true);
+ return stopFlag;
+}
+
+#pragma mark -
+#pragma mark VMDPlayer - Rendering
+
+void VMDPlayer::renderFrame() const {
+ // This writes directly to the CelObjMem we already created,
+ // so no need to take its return value
+ _decoder->decodeNextFrame();
+
+ // NOTE: Normally this would write a hunk palette at the end of the
+ // video bitmap that CelObjMem would read out and submit, but instead
+ // we are just submitting it directly here because the decoder exposes
+ // this information a little bit differently than the one in SSCI
+ const bool dirtyPalette = _decoder->hasDirtyPalette();
+ if (dirtyPalette) {
+ Palette palette;
+ palette.timestamp = g_sci->getTickCount();
+ for (uint16 i = 0; i < _startColor; ++i) {
+ palette.colors[i].used = false;
+ }
+ for (uint16 i = _endColor; i < 256; ++i) {
+ palette.colors[i].used = false;
+ }
+ if (_blackPalette) {
+ for (uint16 i = _startColor; i <= _endColor; ++i) {
+ palette.colors[i].r = palette.colors[i].g = palette.colors[i].b = 0;
+ palette.colors[i].used = true;
+ }
+ } else {
+ fillPalette(palette);
+ }
+
+ g_sci->_gfxPalette32->submit(palette);
+ g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+ g_sci->_gfxFrameout->frameOut(true);
+
+ if (_blackPalette) {
+ fillPalette(palette);
+ g_sci->_gfxPalette32->submit(palette);
+ g_sci->_gfxPalette32->updateForFrame();
+ g_sci->_gfxPalette32->updateHardware();
+ }
+ } else {
+ g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
+ g_sci->getSciDebugger()->onFrame();
+ g_sci->_gfxFrameout->frameOut(true);
+ g_sci->_gfxFrameout->throttle();
+ }
+}
+
+void VMDPlayer::fillPalette(Palette &palette) const {
+ const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
+ for (uint16 i = _startColor; i <= _endColor; ++i) {
+ int16 r = *vmdPalette++;
+ int16 g = *vmdPalette++;
+ int16 b = *vmdPalette++;
+
+ if (_boostPercent != 100 && i >= _boostStartColor && i <= _boostEndColor) {
+ r = CLIP<int16>(r * _boostPercent / 100, 0, 255);
+ g = CLIP<int16>(g * _boostPercent / 100, 0, 255);
+ b = CLIP<int16>(b * _boostPercent / 100, 0, 255);
+ }
+
+ palette.colors[i].r = r;
+ palette.colors[i].g = g;
+ palette.colors[i].b = b;
+ palette.colors[i].used = true;
+ }
+}
+
+#pragma mark -
+#pragma mark VMDPlayer - Palette
+
+void VMDPlayer::restrictPalette(const uint8 startColor, const int16 endColor) {
+ _startColor = startColor;
+ // At least GK2 sends 256 as the end color, which is wrong,
+ // but works in the original engine as the storage size is 4 bytes
+ // and used values are clamped to 0-255
+ _endColor = MIN((int16)255, endColor);
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h
new file mode 100644
index 0000000000..7033f7c647
--- /dev/null
+++ b/engines/sci/graphics/video32.h
@@ -0,0 +1,312 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_GRAPHICS_VIDEO32_H
+#define SCI_GRAPHICS_VIDEO32_H
+
+namespace Video { class AdvancedVMDDecoder; }
+namespace Sci {
+class Plane;
+class ScreenItem;
+class SegManager;
+
+#pragma mark VMDPlayer
+
+/**
+ * VMDPlayer is used to play VMD videos.
+ */
+class VMDPlayer {
+public:
+ enum OpenFlags {
+ kOpenFlagNone = 0,
+ kOpenFlagMute = 1
+ };
+
+ enum IOStatus {
+ kIOSuccess = 0,
+ kIOError = 0xFFFF
+ };
+
+ enum PlayFlags {
+ kPlayFlagNone = 0,
+ kPlayFlagDoublePixels = 1,
+ kPlayFlagBlackLines = 4,
+ kPlayFlagBoost = 0x10,
+ kPlayFlagLeaveScreenBlack = 0x20,
+ kPlayFlagLeaveLastFrame = 0x40,
+ kPlayFlagBlackPalette = 0x80,
+ kPlayFlagStretchVertical = 0x100
+ };
+
+ enum EventFlags {
+ kEventFlagNone = 0,
+ kEventFlagEnd = 1,
+ kEventFlagEscapeKey = 2,
+ kEventFlagMouseDown = 4,
+ kEventFlagHotRectangle = 8,
+ kEventFlagToFrame = 0x10,
+ kEventFlagYieldToVM = 0x20,
+ kEventFlagReverse = 0x80
+ };
+
+ VMDPlayer(SegManager *segMan, EventManager *eventMan);
+ ~VMDPlayer();
+
+private:
+ SegManager *_segMan;
+ EventManager *_eventMan;
+ Video::AdvancedVMDDecoder *_decoder;
+
+#pragma mark -
+#pragma mark VMDPlayer - Playback
+public:
+ /**
+ * Opens a stream to a VMD resource.
+ */
+ IOStatus open(const Common::String &fileName, const OpenFlags flags);
+
+ /**
+ * Initializes the VMD rendering parameters for the
+ * current VMD. This must be called after `open`.
+ */
+ void init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor);
+
+ /**
+ * Stops playback and closes the currently open VMD stream.
+ */
+ IOStatus close();
+
+ // NOTE: Was WaitForEvent in SSCI
+ EventFlags kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval);
+
+private:
+ /**
+ * Whether or not a VMD stream has been opened with
+ * `open`.
+ */
+ bool _isOpen;
+
+ /**
+ * Whether or not a VMD player has been initialised
+ * with `init`.
+ */
+ bool _isInitialized;
+
+ /**
+ * For VMDs played with the `kEventFlagYieldToVM` flag,
+ * the number of frames that should be rendered until
+ * yielding back to the SCI VM.
+ */
+ int32 _yieldInterval;
+
+ /**
+ * For VMDs played with the `kEventFlagYieldToVM` flag,
+ * the last frame when control of the main thread was
+ * yielded back to the SCI VM.
+ */
+ int _lastYieldedFrameNo;
+
+ /**
+ * Plays the VMD until an event occurs (e.g. user
+ * presses escape, clicks, etc.).
+ */
+ EventFlags playUntilEvent(const EventFlags flags);
+
+#pragma mark -
+#pragma mark VMDPlayer - Rendering
+private:
+ /**
+ * The location of the VMD plane, in game script
+ * coordinates.
+ */
+ int16 _x, _y;
+
+ /**
+ * The plane where the VMD will be drawn.
+ */
+ Plane *_plane;
+
+ /**
+ * The screen item representing the VMD surface.
+ */
+ ScreenItem *_screenItem;
+
+ // TODO: planeIsOwned and priority are used in SCI3+ only
+
+ /**
+ * If true, the plane for this VMD was set
+ * externally and is not owned by this VMDPlayer.
+ */
+ bool _planeIsOwned;
+
+ /**
+ * The screen priority of the video.
+ * @see ScreenItem::_priority
+ */
+ int _priority;
+
+ /**
+ * Whether or not the video should be pixel doubled.
+ */
+ bool _doublePixels;
+
+ /**
+ * Whether or not the video should be pixel doubled
+ * vertically only.
+ */
+ bool _stretchVertical;
+
+ /**
+ * Whether or not black lines should be rendered
+ * across the video.
+ */
+ bool _blackLines;
+
+ /**
+ * Whether or not the playback area of the VMD
+ * should be left black at the end of playback.
+ */
+ bool _leaveScreenBlack;
+
+ /**
+ * Whether or not the area of the VMD should be left
+ * displaying the final frame of the video.
+ */
+ bool _leaveLastFrame;
+
+ /**
+ * Renders a frame of video to the output bitmap.
+ */
+ void renderFrame() const;
+
+ /**
+ * Fills the given palette with RGB values from
+ * the VMD palette, applying brightness boost if
+ * it is enabled.
+ */
+ void fillPalette(Palette &palette) const;
+
+#pragma mark -
+#pragma mark VMDPlayer - Blackout
+public:
+ /**
+ * Sets the area of the screen that should be blacked out
+ * during VMD playback.
+ */
+ void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; }
+
+private:
+ /**
+ * The dimensions of the blackout plane.
+ */
+ Common::Rect _blackoutRect;
+
+ /**
+ * An optional plane that will be used to black out
+ * areas of the screen outside of the VMD surface.
+ */
+ Plane *_blackoutPlane;
+
+#pragma mark -
+#pragma mark VMDPlayer - Palette
+public:
+ /**
+ * Restricts use of the system palette by VMD playback to
+ * the given range of palette indexes.
+ */
+ void restrictPalette(const uint8 startColor, const int16 endColor);
+
+private:
+ /**
+ * The first color in the system palette that the VMD
+ * can write to.
+ */
+ uint8 _startColor;
+
+ /**
+ * The last color in the system palette that the VMD
+ * can write to.
+ */
+ uint8 _endColor;
+
+ /**
+ * If true, video frames are rendered after a blank
+ * palette is submitted to the palette manager,
+ * which is then restored after the video pixels
+ * have already been rendered.
+ */
+ bool _blackPalette;
+
+#pragma mark -
+#pragma mark VMDPlayer - Brightness boost
+private:
+ /**
+ * The amount of brightness boost for the video.
+ * Values above 100 increase brightness; values below
+ * 100 reduce it.
+ */
+ int16 _boostPercent;
+
+ /**
+ * The first color in the palette that should be
+ * brightness boosted.
+ */
+ uint8 _boostStartColor;
+
+ /**
+ * The last color in the palette that should be
+ * brightness boosted.
+ */
+ uint8 _boostEndColor;
+
+#pragma mark -
+#pragma mark VMDPlayer - Mouse cursor
+public:
+ /**
+ * Sets whether or not the mouse cursor should be drawn.
+ * This does not have any effect during playback, but can
+ * be used to prevent the mouse cursor from being shown
+ * again after the video has finished.
+ */
+ void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; }
+
+private:
+ /**
+ * Whether or not the mouse cursor should be shown
+ * during playback.
+ */
+ bool _showCursor;
+};
+
+class Video32 {
+public:
+ Video32(SegManager *segMan, EventManager *eventMan) :
+ _VMDPlayer(segMan, eventMan) {}
+
+ VMDPlayer &getVMDPlayer() { return _VMDPlayer; }
+
+private:
+ VMDPlayer _VMDPlayer;
+};
+} // End of namespace Sci
+
+#endif
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 4116eda876..1939e66179 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -25,6 +25,7 @@
#include "sci/engine/state.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/view.h"
@@ -842,12 +843,11 @@ void GfxView::draw(const Common::Rect &rect, const Common::Rect &clipRect, const
const int y2 = clipRectTranslated.top + y;
if (!upscaledHires) {
if (priority >= _screen->getPriority(x2, y2)) {
- if (!_palette->isRemapped(palette->mapping[color])) {
- _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0);
- } else {
- byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2));
- _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0);
- }
+ byte outputColor = palette->mapping[color];
+ // SCI16 remapping (QFG4 demo)
+ if (g_sci->_gfxRemap16 && g_sci->_gfxRemap16->isRemapped(outputColor))
+ outputColor = g_sci->_gfxRemap16->remapColor(outputColor, _screen->getVisual(x2, y2));
+ _screen->putPixel(x2, y2, drawMask, outputColor, priority, 0);
}
} else {
// UpscaledHires means view is hires and is supposed to
@@ -957,12 +957,11 @@ void GfxView::drawScaled(const Common::Rect &rect, const Common::Rect &clipRect,
const int x2 = clipRectTranslated.left + x;
const int y2 = clipRectTranslated.top + y;
if (color != clearKey && priority >= _screen->getPriority(x2, y2)) {
- if (!_palette->isRemapped(palette->mapping[color])) {
- _screen->putPixel(x2, y2, drawMask, palette->mapping[color], priority, 0);
- } else {
- byte remappedColor = _palette->remapColor(palette->mapping[color], _screen->getVisual(x2, y2));
- _screen->putPixel(x2, y2, drawMask, remappedColor, priority, 0);
- }
+ byte outputColor = palette->mapping[color];
+ // SCI16 remapping (QFG4 demo)
+ if (g_sci->_gfxRemap16 && g_sci->_gfxRemap16->isRemapped(outputColor))
+ outputColor = g_sci->_gfxRemap16->remapColor(outputColor, _screen->getVisual(x2, y2));
+ _screen->putPixel(x2, y2, drawMask, outputColor, priority, 0);
}
}
}
@@ -976,13 +975,4 @@ void GfxView::adjustBackUpscaledCoordinates(int16 &y, int16 &x) {
_screen->adjustBackUpscaledCoordinates(y, x, _sci2ScaleRes);
}
-byte GfxView::getColorAtCoordinate(int16 loopNo, int16 celNo, int16 x, int16 y) {
- const CelInfo *celInfo = getCelInfo(loopNo, celNo);
- const byte *bitmap = getBitmap(loopNo, celNo);
- const int16 celWidth = celInfo->width;
-
- bitmap += (celWidth * y);
- return bitmap[x];
-}
-
} // End of namespace Sci
diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h
index d8803db208..96b48c0477 100644
--- a/engines/sci/graphics/view.h
+++ b/engines/sci/graphics/view.h
@@ -55,6 +55,7 @@ struct LoopInfo {
class GfxScreen;
class GfxPalette;
+class Resource;
/**
* View class, handles loading of view resources and drawing contained cels to screen
@@ -85,8 +86,6 @@ public:
void adjustToUpscaledCoordinates(int16 &y, int16 &x);
void adjustBackUpscaledCoordinates(int16 &y, int16 &x);
- byte getColorAtCoordinate(int16 loopNo, int16 celNo, int16 x, int16 y);
-
private:
void initData(GuiResourceId resourceId);
void unpackCel(int16 loopNo, int16 celNo, byte *outPtr, uint32 pixelCount);
diff --git a/engines/sci/module.mk b/engines/sci/module.mk
index 963b65742d..1511356747 100644
--- a/engines/sci/module.mk
+++ b/engines/sci/module.mk
@@ -51,12 +51,12 @@ MODULE_OBJS := \
graphics/fontsjis.o \
graphics/maciconbar.o \
graphics/menu.o \
- graphics/paint.o \
graphics/paint16.o \
graphics/palette.o \
graphics/picture.o \
graphics/portrait.o \
graphics/ports.o \
+ graphics/remap.o \
graphics/screen.o \
graphics/text16.o \
graphics/transitions.o \
@@ -68,6 +68,7 @@ MODULE_OBJS := \
sound/midiparser_sci.o \
sound/music.o \
sound/soundcmd.o \
+ sound/sync.o \
sound/drivers/adlib.o \
sound/drivers/amigamac.o \
sound/drivers/cms.o \
@@ -87,8 +88,12 @@ MODULE_OBJS += \
graphics/paint32.o \
graphics/plane32.o \
graphics/palette32.o \
+ graphics/remap32.o \
graphics/screen_item32.o \
graphics/text32.o \
+ graphics/video32.o \
+ sound/audio32.o \
+ sound/decoders/sol.o \
video/robot_decoder.o
endif
diff --git a/engines/sci/parser/vocabulary.cpp b/engines/sci/parser/vocabulary.cpp
index 828a57abeb..a09ba8f3ce 100644
--- a/engines/sci/parser/vocabulary.cpp
+++ b/engines/sci/parser/vocabulary.cpp
@@ -121,7 +121,7 @@ bool Vocabulary::loadParserWords() {
}
}
- unsigned int seeker;
+ uint32 seeker;
if (resourceType == kVocabularySCI1)
seeker = 255 * 2; // vocab.900 starts with 255 16-bit pointers which we don't use
else
@@ -202,7 +202,7 @@ bool Vocabulary::loadSuffixes() {
if (!resource)
return false; // No vocabulary found
- unsigned int seeker = 1;
+ uint32 seeker = 1;
while ((seeker < resource->size - 1) && (resource->data[seeker + 1] != 0xff)) {
suffix_t suffix;
@@ -288,7 +288,7 @@ bool Vocabulary::loadAltInputs() {
AltInput t;
t._input = data;
- unsigned int l = strlen(data);
+ uint32 l = strlen(data);
t._inputLength = l;
data += l + 1;
@@ -325,15 +325,15 @@ bool Vocabulary::checkAltInput(Common::String& text, uint16& cursorPos) {
return false;
bool ret = false;
- unsigned int loopCount = 0;
+ uint32 loopCount = 0;
bool changed;
do {
changed = false;
const char* t = text.c_str();
- unsigned int tlen = text.size();
+ uint32 tlen = text.size();
- for (unsigned int p = 0; p < tlen && !changed; ++p) {
+ for (uint32 p = 0; p < tlen && !changed; ++p) {
unsigned char s = t[p];
if (s >= _altInputs.size() || _altInputs[s].empty())
continue;
@@ -351,7 +351,7 @@ bool Vocabulary::checkAltInput(Common::String& text, uint16& cursorPos) {
cursorPos = p + strlen(i->_replacement);
}
- for (unsigned int j = 0; j < i->_inputLength; ++j)
+ for (uint32 j = 0; j < i->_inputLength; ++j)
text.deleteChar(p);
const char *r = i->_replacement;
while (*r)
diff --git a/engines/sci/parser/vocabulary.h b/engines/sci/parser/vocabulary.h
index f4adee6e55..59558ce18a 100644
--- a/engines/sci/parser/vocabulary.h
+++ b/engines/sci/parser/vocabulary.h
@@ -156,7 +156,7 @@ typedef Common::Array<synonym_t> SynonymList;
struct AltInput {
const char *_input;
const char *_replacement;
- unsigned int _inputLength;
+ uint32 _inputLength;
bool _prefix;
};
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 2a4cd95b91..48278e35a7 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -26,6 +26,9 @@
#include "common/fs.h"
#include "common/macresman.h"
#include "common/textconsole.h"
+#ifdef ENABLE_SCI32
+#include "common/memstream.h"
+#endif
#include "sci/resource.h"
#include "sci/resource_intern.h"
@@ -221,6 +224,12 @@ void Resource::writeToStream(Common::WriteStream *stream) const {
stream->write(data, size);
}
+#ifdef ENABLE_SCI32
+Common::SeekableReadStream *Resource::makeStream() const {
+ return new Common::MemoryReadStream(data, size, DisposeAfterUse::NO);
+}
+#endif
+
uint32 Resource::getAudioCompressionType() const {
return _source->getAudioCompressionType();
}
@@ -229,7 +238,6 @@ uint32 AudioVolumeResourceSource::getAudioCompressionType() const {
return _audioCompressionType;
}
-
ResourceSource::ResourceSource(ResSourceType type, const Common::String &name, int volNum, const Common::FSNode *resFile)
: _sourceType(type), _name(name), _volumeNumber(volNum), _resourceFile(resFile) {
_scanned = false;
@@ -307,7 +315,7 @@ bool Resource::loadPatch(Common::SeekableReadStream *file) {
error("Can't allocate %d bytes needed for loading %s", res->size + res->_headerSize, res->_id.toString().c_str());
}
- unsigned int really_read;
+ uint32 really_read;
if (res->_headerSize > 0) {
really_read = file->read(res->_header, res->_headerSize);
if (really_read != res->_headerSize)
@@ -565,12 +573,11 @@ Resource *ResourceManager::testResource(ResourceId id) {
}
int ResourceManager::addAppropriateSources() {
- Common::ArchiveMemberList files;
-
if (Common::File::exists("resource.map")) {
// SCI0-SCI2 file naming scheme
ResourceSource *map = addExternalMap("resource.map");
+ Common::ArchiveMemberList files;
SearchMan.listMatchingMembers(files, "resource.0??");
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
@@ -587,20 +594,20 @@ int ResourceManager::addAppropriateSources() {
#endif
} else if (Common::MacResManager::exists("Data1")) {
// Mac SCI1.1+ file naming scheme
- SearchMan.listMatchingMembers(files, "Data?*");
+ Common::StringArray files;
+ Common::MacResManager::listFiles(files, "Data?");
- for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
- Common::String filename = (*x)->getName();
- addSource(new MacResourceForkResourceSource(filename, atoi(filename.c_str() + 4)));
+ for (Common::StringArray::const_iterator x = files.begin(); x != files.end(); ++x) {
+ addSource(new MacResourceForkResourceSource(*x, atoi(x->c_str() + 4)));
}
#ifdef ENABLE_SCI32
// There can also be a "Patches" resource fork with patches
- if (Common::File::exists("Patches"))
+ if (Common::MacResManager::exists("Patches"))
addSource(new MacResourceForkResourceSource("Patches", 100));
} else {
// SCI2.1-SCI3 file naming scheme
- Common::ArchiveMemberList mapFiles;
+ Common::ArchiveMemberList mapFiles, files;
SearchMan.listMatchingMembers(mapFiles, "resmap.0??");
SearchMan.listMatchingMembers(files, "ressci.0??");
@@ -1044,7 +1051,13 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) {
if (retval->_status == kResStatusNoMalloc)
loadResource(retval);
else if (retval->_status == kResStatusEnqueued)
+ // The resource is removed from its current position
+ // in the LRU list because it has been requested
+ // again. Below, it will either be locked, or it
+ // will be added back to the LRU list at the 'most
+ // recent' position.
removeFromLRU(retval);
+
// Unless an error occurred, the resource is now either
// locked or allocated, but never queued or freed.
@@ -1353,6 +1366,8 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
Common::File *file = new Common::File();
if (!file->open(source->getLocationName())) {
warning("ResourceManager::processPatch(): failed to open %s", source->getLocationName().c_str());
+ delete source;
+ delete file;
return;
}
fileStream = file;
@@ -1361,6 +1376,8 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
int fsize = fileStream->size();
if (fsize < 3) {
debug("Patching %s failed - file too small", source->getLocationName().c_str());
+ delete source;
+ delete fileStream;
return;
}
@@ -1371,6 +1388,7 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
if (patchType != checkForType) {
debug("Patching %s failed - resource type mismatch", source->getLocationName().c_str());
+ delete source;
return;
}
@@ -1395,6 +1413,7 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType resource
if (patchDataOffset + 2 >= fsize) {
debug("Patching %s failed - patch starting at offset %d can't be in file of size %d",
source->getLocationName().c_str(), patchDataOffset + 2, fsize);
+ delete source;
return;
}
@@ -1442,13 +1461,18 @@ void ResourceManager::readResourcePatchesBase36() {
files.clear();
// audio36 resources start with a @, A, or B
- // sync36 resources start with a #
+ // sync36 resources start with a #, S, or T
if (i == kResourceTypeAudio36) {
SearchMan.listMatchingMembers(files, "@???????.???");
SearchMan.listMatchingMembers(files, "A???????.???");
SearchMan.listMatchingMembers(files, "B???????.???");
- } else
+ } else {
SearchMan.listMatchingMembers(files, "#???????.???");
+#ifdef ENABLE_SCI32
+ SearchMan.listMatchingMembers(files, "S???????.???");
+ SearchMan.listMatchingMembers(files, "T???????.???");
+#endif
+ }
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) {
name = (*x)->getName();
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index ef474d97c2..f70bf48bd4 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -84,7 +84,10 @@ enum ResourceType {
kResourceTypePatch,
kResourceTypeBitmap,
kResourceTypePalette,
- kResourceTypeCdAudio,
+ kResourceTypeCdAudio = 12,
+#ifdef ENABLE_SCI32
+ kResourceTypeWave = 12,
+#endif
kResourceTypeAudio,
kResourceTypeSync,
kResourceTypeMessage,
@@ -212,6 +215,10 @@ public:
return (_type == other._type) && (_number == other._number) && (_tuple == other._tuple);
}
+ bool operator!=(const ResourceId &other) const {
+ return !operator==(other);
+ }
+
bool operator<(const ResourceId &other) const {
return (_type < other._type) || ((_type == other._type) && (_number < other._number))
|| ((_type == other._type) && (_number == other._number) && (_tuple < other._tuple));
@@ -259,6 +266,10 @@ public:
*/
void writeToStream(Common::WriteStream *stream) const;
+#ifdef ENABLE_SCI32
+ Common::SeekableReadStream *makeStream() const;
+#endif
+
const Common::String &getResourceLocation() const;
// FIXME: This audio specific method is a hack. After all, why should a
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index 6869e6379e..5ab443a16d 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -25,7 +25,7 @@
#include "common/archive.h"
#include "common/file.h"
#include "common/textconsole.h"
-
+#include "common/memstream.h"
#include "sci/resource.h"
#include "sci/resource_intern.h"
#include "sci/util.h"
@@ -139,7 +139,7 @@ bool Resource::loadFromAudioVolumeSCI1(Common::SeekableReadStream *file) {
error("Can't allocate %d bytes needed for loading %s", size, _id.toString().c_str());
}
- unsigned int really_read = file->read(data, size);
+ uint32 really_read = file->read(data, size);
if (really_read != size)
warning("Read %d bytes from %s but expected %d", really_read, _id.toString().c_str(), size);
@@ -688,6 +688,12 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
channel->data = resource->data + dataOffset;
channel->size = READ_LE_UINT16(data + 4);
+
+ if (dataOffset + channel->size > resource->size) {
+ warning("Invalid size inside sound resource %d: track %d, channel %d", resourceNr, trackNr, channelNr);
+ channel->size = resource->size - dataOffset;
+ }
+
channel->curPos = 0;
channel->number = *channel->data;
@@ -863,6 +869,7 @@ void WaveResourceSource::loadResource(ResourceManager *resMan, Resource *res) {
if (!fileStream)
return;
+ assert(fileStream->size() == -1 || res->_fileOffset < fileStream->size());
fileStream->seek(res->_fileOffset, SEEK_SET);
res->loadFromWaveFile(fileStream);
if (_resourceFile)
@@ -916,6 +923,7 @@ void AudioVolumeResourceSource::loadResource(ResourceManager *resMan, Resource *
break;
}
} else {
+ assert(fileStream->size() == -1 || res->_fileOffset < fileStream->size());
// original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
fileStream->seek(res->_fileOffset, SEEK_SET);
}
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 6d36fabde9..3ea2756f56 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -43,12 +43,12 @@
#include "sci/sound/audio.h"
#include "sci/sound/music.h"
+#include "sci/sound/sync.h"
#include "sci/sound/soundcmd.h"
#include "sci/graphics/animate.h"
#include "sci/graphics/cache.h"
#include "sci/graphics/compare.h"
#include "sci/graphics/controls16.h"
-#include "sci/graphics/controls32.h"
#include "sci/graphics/coordadjuster.h"
#include "sci/graphics/cursor.h"
#include "sci/graphics/maciconbar.h"
@@ -58,14 +58,20 @@
#include "sci/graphics/picture.h"
#include "sci/graphics/ports.h"
#include "sci/graphics/palette.h"
+#include "sci/graphics/remap.h"
#include "sci/graphics/screen.h"
#include "sci/graphics/text16.h"
#include "sci/graphics/transitions.h"
#ifdef ENABLE_SCI32
+#include "sci/graphics/controls32.h"
+#include "sci/graphics/frameout.h"
#include "sci/graphics/palette32.h"
+#include "sci/graphics/remap32.h"
#include "sci/graphics/text32.h"
-#include "sci/graphics/frameout.h"
+#include "sci/graphics/video32.h"
+#include "sci/sound/audio32.h"
+// TODO: Move this to video32
#include "sci/video/robot_decoder.h"
#endif
@@ -85,6 +91,11 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
_gfxMacIconBar = 0;
_audio = 0;
+ _sync = nullptr;
+#ifdef ENABLE_SCI32
+ _audio32 = nullptr;
+ _video32 = nullptr;
+#endif
_features = 0;
_resMan = 0;
_gamestate = 0;
@@ -156,29 +167,36 @@ SciEngine::~SciEngine() {
DebugMan.clearAllDebugChannels();
#ifdef ENABLE_SCI32
- // _gfxPalette32 is the same as _gfxPalette16
- // and will be destroyed when _gfxPalette16 is
- // destroyed
delete _gfxControls32;
+ delete _gfxPaint32;
delete _gfxText32;
delete _robotDecoder;
+ // GfxFrameout and GfxPalette32 must be deleted after Video32 since
+ // destruction of screen items in the Video32 destructor relies on these
+ // components
+ delete _video32;
+ delete _gfxPalette32;
delete _gfxFrameout;
+ delete _gfxRemap32;
+ delete _audio32;
#endif
delete _gfxMenu;
delete _gfxControls16;
delete _gfxText16;
delete _gfxAnimate;
- delete _gfxPaint;
+ delete _gfxPaint16;
delete _gfxTransitions;
delete _gfxCompare;
delete _gfxCoordAdjuster;
delete _gfxPorts;
delete _gfxCache;
delete _gfxPalette16;
+ delete _gfxRemap16;
delete _gfxCursor;
delete _gfxScreen;
delete _audio;
+ delete _sync;
delete _soundCmd;
delete _kernel;
delete _vocabulary;
@@ -238,13 +256,7 @@ Common::Error SciEngine::run() {
// Only DOS+Windows
switch (_gameId) {
case GID_KQ6:
- if (isCD())
- _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
- break;
case GID_GK1:
- if ((isCD()) && (!isDemo()))
- _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
- break;
case GID_PQ4:
if (isCD())
_forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics");
@@ -269,9 +281,21 @@ Common::Error SciEngine::run() {
// Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135
if (getGameId() == GID_CHRISTMAS1990)
_vocabulary = new Vocabulary(_resMan, false);
- _audio = new AudioPlayer(_resMan);
+
_gamestate = new EngineState(segMan);
_eventMan = new EventManager(_resMan->detectFontExtended());
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
+ _audio32 = new Audio32(_resMan);
+ } else
+#endif
+ _audio = new AudioPlayer(_resMan);
+#ifdef ENABLE_SCI32
+ if (getSciVersion() >= SCI_VERSION_2) {
+ _video32 = new Video32(segMan, _eventMan);
+ }
+#endif
+ _sync = new Sync(_resMan, segMan);
// Create debugger console. It requires GFX and _gamestate to be initialized
_console = new Console(this);
@@ -316,6 +340,7 @@ Common::Error SciEngine::run() {
if (directSaveSlotLoading >= 0) {
_gamestate->_delayedRestoreGame = true;
_gamestate->_delayedRestoreGameId = directSaveSlotLoading;
+ _gamestate->_delayedRestoreFromLauncher = true;
// Jones only initializes its menus when restarting/restoring, thus set
// the gameIsRestarting flag here before initializing. Fixes bug #6536.
@@ -343,6 +368,17 @@ Common::Error SciEngine::run() {
}
}
+ if (getGameId() == GID_KQ7 && ConfMan.getBool("subtitles")) {
+ showScummVMDialog("Subtitles are enabled, but subtitling in King's"
+ " Quest 7 was unfinished and disabled in the release"
+ " version of the game. ScummVM allows the subtitles"
+ " to be re-enabled, but because they were removed from"
+ " the original game, they do not always render"
+ " properly or reflect the actual game speech."
+ " This is not a ScummVM bug -- it is a problem with"
+ " the game's assets.");
+ }
+
// Show a warning if the user has selected a General MIDI device, no GM patch exists
// (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided
// after market patches for in their "General MIDI Utility".
@@ -662,9 +698,9 @@ void SciEngine::initGraphics() {
_gfxCursor = 0;
_gfxMacIconBar = 0;
_gfxMenu = 0;
- _gfxPaint = 0;
_gfxPaint16 = 0;
_gfxPalette16 = 0;
+ _gfxRemap16 = 0;
_gfxPorts = 0;
_gfxText16 = 0;
_gfxTransitions = 0;
@@ -675,6 +711,7 @@ void SciEngine::initGraphics() {
_gfxFrameout = 0;
_gfxPaint32 = 0;
_gfxPalette32 = 0;
+ _gfxRemap32 = 0;
#endif
if (hasMacIconBar())
@@ -682,11 +719,13 @@ void SciEngine::initGraphics() {
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2) {
- _gfxPalette32 = new GfxPalette32(_resMan, _gfxScreen);
- _gfxPalette16 = _gfxPalette32;
+ _gfxPalette32 = new GfxPalette32(_resMan);
+ _gfxRemap32 = new GfxRemap32();
} else {
#endif
_gfxPalette16 = new GfxPalette(_resMan, _gfxScreen);
+ if (getGameId() == GID_QFG4DEMO)
+ _gfxRemap16 = new GfxRemap(_gfxPalette16);
#ifdef ENABLE_SCI32
}
#endif
@@ -700,11 +739,10 @@ void SciEngine::initGraphics() {
_gfxCoordAdjuster = new GfxCoordAdjuster32(_gamestate->_segMan);
_gfxCursor->init(_gfxCoordAdjuster, _eventMan);
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
- _gfxPaint32 = new GfxPaint32(_resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32);
- _gfxPaint = _gfxPaint32;
+ _gfxPaint32 = new GfxPaint32(_gamestate->_segMan);
_robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh);
- _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32);
- _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen);
+ _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32);
+ _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache);
_gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32);
_gfxFrameout->run();
} else {
@@ -716,7 +754,6 @@ void SciEngine::initGraphics() {
_gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster);
_gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16);
_gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio);
- _gfxPaint = _gfxPaint16;
_gfxAnimate = new GfxAnimate(_gamestate, _scriptPatcher, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions);
_gfxText16 = new GfxText16(_gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen);
_gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen);
@@ -731,8 +768,10 @@ void SciEngine::initGraphics() {
}
#endif
- // Set default (EGA, amiga or resource 999) palette
- _gfxPalette16->setDefault();
+ if (getSciVersion() < SCI_VERSION_2) {
+ // Set default (EGA, amiga or resource 999) palette
+ _gfxPalette16->setDefault();
+ }
}
void SciEngine::initStackBaseWithSelector(Selector selector) {
@@ -798,7 +837,10 @@ void SciEngine::runGame() {
void SciEngine::exitGame() {
if (_gamestate->abortScriptProcessing != kAbortLoadGame) {
_gamestate->_executionStack.clear();
- _audio->stopAllAudio();
+ if (_audio) {
+ _audio->stopAllAudio();
+ }
+ _sync->stop();
_soundCmd->clearPlayList();
}
@@ -833,7 +875,7 @@ Console *SciEngine::getSciDebugger() {
}
const char *SciEngine::getGameIdStr() const {
- return _gameDescription->gameid;
+ return _gameDescription->gameId;
}
Common::Language SciEngine::getLanguage() const {
@@ -894,6 +936,10 @@ Common::String SciEngine::unwrapFilename(const Common::String &name) const {
return name;
}
+const char *SciEngine::getGameObjectName() {
+ return _gamestate->_segMan->getObjectName(_gameObjectAddress);
+}
+
int SciEngine::inQfGImportRoom() const {
if (_gameId == GID_QFG2 && _gamestate->currentRoomNumber() == 805) {
// QFG2 character import screen
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index 3945e68e33..0020d25b91 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SCI_H
-#define SCI_H
+#ifndef SCI_SCI_H
+#define SCI_SCI_H
#include "engines/engine.h"
#include "common/macresman.h"
@@ -56,6 +56,7 @@ class SoundCommandParser;
class EventManager;
class SegManager;
class ScriptPatcher;
+class Sync;
class GfxAnimate;
class GfxCache;
@@ -66,11 +67,12 @@ class GfxCoordAdjuster;
class GfxCursor;
class GfxMacIconBar;
class GfxMenu;
-class GfxPaint;
class GfxPaint16;
class GfxPaint32;
class GfxPalette;
class GfxPalette32;
+class GfxRemap;
+class GfxRemap32;
class GfxPorts;
class GfxScreen;
class GfxText16;
@@ -78,8 +80,11 @@ class GfxText32;
class GfxTransitions;
#ifdef ENABLE_SCI32
+// TODO: Move RobotDecoder to Video32
class RobotDecoder;
class GfxFrameout;
+class Audio32;
+class Video32;
#endif
// our engine debug levels
@@ -128,13 +133,16 @@ enum SciGameId {
GID_FAIRYTALES,
GID_FREDDYPHARKAS,
GID_FUNSEEKER,
+ GID_GK1DEMO, // We have a separate ID for GK1 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1)
GID_GK1,
GID_GK2,
GID_HOYLE1,
GID_HOYLE2,
GID_HOYLE3,
GID_HOYLE4,
+ GID_HOYLE5,
GID_ICEMAN,
+ GID_INNDEMO,
GID_ISLANDBRAIN,
GID_JONES,
GID_KQ1,
@@ -165,12 +173,14 @@ enum SciGameId {
GID_PQ2,
GID_PQ3,
GID_PQ4,
+ GID_PQ4DEMO, // We have a separate ID for PQ4 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1)
GID_PQSWAT,
GID_QFG1,
GID_QFG1VGA,
GID_QFG2,
GID_QFG3,
GID_QFG4,
+ GID_QFG4DEMO, // We have a separate ID for QFG4 demo, because it's actually a completely different game (SCI1.1 vs SCI2/SCI2.1)
GID_RAMA,
GID_SHIVERS,
//GID_SHIVERS2, // Not SCI
@@ -201,8 +211,8 @@ enum SciVersion {
SCI_VERSION_1_LATE, // Dr. Brain 1, EcoQuest 1, Longbow, PQ3, SQ1, LSL5, KQ5 CD
SCI_VERSION_1_1, // Dr. Brain 2, EcoQuest 1 CD, EcoQuest 2, KQ6, QFG3, SQ4CD, XMAS 1992 and many more
SCI_VERSION_2, // GK1, PQ4 floppy, QFG4 floppy
- SCI_VERSION_2_1_EARLY, // GK2 demo, KQ7, LSL6 hires, PQ4, QFG4 floppy
- SCI_VERSION_2_1_MIDDLE, // GK2, KQ7, MUMG Deluxe, Phantasmagoria 1, PQ4CD, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
+ SCI_VERSION_2_1_EARLY, // GK2 demo, KQ7 1.4/1.51, LSL6 hires, PQ4CD, QFG4 floppy
+ SCI_VERSION_2_1_MIDDLE, // GK2, KQ7 2.00b, MUMG Deluxe, Phantasmagoria 1, PQ:SWAT, QFG4CD, Shivers 1, SQ6, Torin
SCI_VERSION_2_1_LATE, // demos of LSL7, Lighthouse, RAMA
SCI_VERSION_3 // LSL7, Lighthouse, RAMA, Phantasmagoria 2
};
@@ -297,6 +307,8 @@ public:
/** Remove the 'TARGET-' prefix of the given filename, if present. */
Common::String unwrapFilename(const Common::String &name) const;
+ const char *getGameObjectName(); // Gets the name of the game object (should only be used for identifying fanmade games)
+
/**
* Checks if we are in a QfG import screen, where special handling
* of file-listings is performed.
@@ -349,7 +361,8 @@ public:
GfxMenu *_gfxMenu; // Menu for 16-bit gfx
GfxPalette *_gfxPalette16;
GfxPalette32 *_gfxPalette32; // Palette for 32-bit gfx
- GfxPaint *_gfxPaint;
+ GfxRemap *_gfxRemap16; // Remapping for the QFG4 demo
+ GfxRemap32 *_gfxRemap32; // Remapping for 32-bit gfx
GfxPaint16 *_gfxPaint16; // Painting in 16-bit gfx
GfxPaint32 *_gfxPaint32; // Painting in 32-bit gfx
GfxPorts *_gfxPorts; // Port managment for 16-bit gfx
@@ -360,11 +373,14 @@ public:
GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager
#ifdef ENABLE_SCI32
+ Audio32 *_audio32;
+ Video32 *_video32;
RobotDecoder *_robotDecoder;
GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
#endif
AudioPlayer *_audio;
+ Sync *_sync;
SoundCommandParser *_soundCmd;
GameFeatures *_features;
@@ -453,4 +469,4 @@ const char *getSciVersionDesc(SciVersion version);
} // End of namespace Sci
-#endif // SCI_H
+#endif // SCI_SCI_H
diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp
index 57f0415285..4fb9a58003 100644
--- a/engines/sci/sound/audio.cpp
+++ b/engines/sci/sound/audio.cpp
@@ -22,12 +22,12 @@
#include "sci/resource.h"
#include "sci/engine/kernel.h"
-#include "sci/engine/selector.h"
#include "sci/engine/seg_manager.h"
#include "sci/sound/audio.h"
#include "backends/audiocd/audiocd.h"
+#include "common/config-manager.h"
#include "common/file.h"
#include "common/memstream.h"
#include "common/system.h"
@@ -44,7 +44,7 @@
namespace Sci {
AudioPlayer::AudioPlayer(ResourceManager *resMan) : _resMan(resMan), _audioRate(11025),
- _syncResource(NULL), _syncOffset(0), _audioCdStart(0) {
+ _audioCdStart(0), _initCD(false) {
_mixer = g_system->getMixer();
_wPlayFlag = false;
@@ -55,7 +55,6 @@ AudioPlayer::~AudioPlayer() {
}
void AudioPlayer::stopAllAudio() {
- stopSoundSync();
stopAudio();
if (_audioCdStart > 0)
audioCdStop();
@@ -254,13 +253,7 @@ static void deDPCM16(byte *soundBuf, Common::SeekableReadStream &audioStream, ui
static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) {
if (b & 8) {
-#ifdef ENABLE_SCI32
- // SCI2.1 reverses the order of the table values here
- if (getSciVersion() >= SCI_VERSION_2_1_EARLY)
- s -= tableDPCM8[b & 7];
- else
-#endif
- s -= tableDPCM8[7 - (b & 7)];
+ s -= tableDPCM8[7 - (b & 7)];
} else
s += tableDPCM8[b & 7];
s = CLIP<int32>(s, 0, 255);
@@ -473,44 +466,13 @@ Audio::RewindableAudioStream *AudioPlayer::getAudioStream(uint32 number, uint32
return NULL;
}
-void AudioPlayer::setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *segMan) {
- _syncResource = _resMan->findResource(id, 1);
- _syncOffset = 0;
-
- if (_syncResource) {
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), 0);
- } else {
- warning("setSoundSync: failed to find resource %s", id.toString().c_str());
- // Notify the scripts to stop sound sync
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
- }
-}
-
-void AudioPlayer::doSoundSync(reg_t syncObjAddr, SegManager *segMan) {
- if (_syncResource && (_syncOffset < _syncResource->size - 1)) {
- int16 syncCue = -1;
- int16 syncTime = (int16)READ_SCI11ENDIAN_UINT16(_syncResource->data + _syncOffset);
-
- _syncOffset += 2;
-
- if ((syncTime != -1) && (_syncOffset < _syncResource->size - 1)) {
- syncCue = (int16)READ_SCI11ENDIAN_UINT16(_syncResource->data + _syncOffset);
- _syncOffset += 2;
- }
-
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
- writeSelectorValue(segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
- }
-}
-
-void AudioPlayer::stopSoundSync() {
- if (_syncResource) {
- _resMan->unlockResource(_syncResource);
- _syncResource = NULL;
+int AudioPlayer::audioCdPlay(int track, int start, int duration) {
+ if (!_initCD) {
+ // Initialize CD mode if we haven't already
+ g_system->getAudioCDManager()->open();
+ _initCD = true;
}
-}
-int AudioPlayer::audioCdPlay(int track, int start, int duration) {
if (getSciVersion() == SCI_VERSION_1_1) {
// King's Quest VI CD Audio format
_audioCdStart = g_system->getMillis();
diff --git a/engines/sci/sound/audio.h b/engines/sci/sound/audio.h
index 9e65d6e0c8..3d25dcaeef 100644
--- a/engines/sci/sound/audio.h
+++ b/engines/sci/sound/audio.h
@@ -46,12 +46,6 @@ enum AudioCommands {
kSciAudioCD = 10 /* Plays SCI1.1 CD audio */
};
-enum AudioSyncCommands {
- kSciAudioSyncStart = 0,
- kSciAudioSyncNext = 1,
- kSciAudioSyncStop = 2
-};
-
#define AUDIO_VOLUME_MAX 127
class Resource;
@@ -77,10 +71,6 @@ public:
void handleFanmadeSciAudio(reg_t sciAudioObject, SegManager *segMan);
- void setSoundSync(ResourceId id, reg_t syncObjAddr, SegManager *segMan);
- void doSoundSync(reg_t syncObjAddr, SegManager *segMan);
- void stopSoundSync();
-
int audioCdPlay(int track, int start, int duration);
void audioCdStop();
void audioCdUpdate();
@@ -93,10 +83,9 @@ private:
uint16 _audioRate;
Audio::SoundHandle _audioHandle;
Audio::Mixer *_mixer;
- Resource *_syncResource; /**< Used by kDoSync for speech syncing in CD talkie games */
- uint _syncOffset;
uint32 _audioCdStart;
bool _wPlayFlag;
+ bool _initCD;
};
} // End of namespace Sci
diff --git a/engines/sci/sound/audio32.cpp b/engines/sci/sound/audio32.cpp
new file mode 100644
index 0000000000..0cf8e3cb13
--- /dev/null
+++ b/engines/sci/sound/audio32.cpp
@@ -0,0 +1,993 @@
+/* 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.
+ *
+ */
+
+#include "sci/sound/audio32.h"
+#include "audio/audiostream.h" // for SeekableAudioStream
+#include "audio/decoders/raw.h" // for makeRawStream, RawFlags::FLAG_16BITS
+#include "audio/decoders/wave.h" // for makeWAVStream
+#include "audio/rate.h" // for RateConverter, makeRateConverter
+#include "audio/timestamp.h" // for Timestamp
+#include "common/config-manager.h" // for ConfMan
+#include "common/endian.h" // for MKTAG
+#include "common/memstream.h" // for MemoryReadStream
+#include "common/str.h" // for String
+#include "common/stream.h" // for SeekableReadStream
+#include "common/system.h" // for OSystem, g_system
+#include "common/textconsole.h" // for warning
+#include "common/types.h" // for Flag::NO
+#include "engine.h" // for Engine, g_engine
+#include "sci/engine/vm_types.h" // for reg_t, make_reg, NULL_REG
+#include "sci/resource.h" // for ResourceId, ResourceType::kResour...
+#include "sci/sci.h" // for SciEngine, g_sci, getSciVersion
+#include "sci/sound/decoders/sol.h" // for makeSOLStream
+
+namespace Sci {
+
+bool detectSolAudio(Common::SeekableReadStream &stream) {
+ const size_t initialPosition = stream.pos();
+
+// TODO: Resource manager for audio resources reads past the
+// header so even though this is the detection algorithm
+// in SSCI, ScummVM can't use it
+#if 0
+ byte header[6];
+ if (stream.read(header, sizeof(header)) != sizeof(header)) {
+ stream.seek(initialPosition);
+ return false;
+ }
+
+ stream.seek(initialPosition);
+
+ if (header[0] != 0x8d || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) {
+ return false;
+ }
+
+ return true;
+#else
+ byte header[4];
+ if (stream.read(header, sizeof(header)) != sizeof(header)) {
+ stream.seek(initialPosition);
+ return false;
+ }
+
+ stream.seek(initialPosition);
+
+ if (READ_BE_UINT32(header) != MKTAG('S', 'O', 'L', 0)) {
+ return false;
+ }
+
+ return true;
+#endif
+}
+
+bool detectWaveAudio(Common::SeekableReadStream &stream) {
+ const size_t initialPosition = stream.pos();
+
+ byte blockHeader[8];
+ if (stream.read(blockHeader, sizeof(blockHeader)) != sizeof(blockHeader)) {
+ stream.seek(initialPosition);
+ return false;
+ }
+
+ stream.seek(initialPosition);
+ const uint32 headerType = READ_BE_UINT32(blockHeader);
+
+ if (headerType != MKTAG('R', 'I', 'F', 'F')) {
+ return false;
+ }
+
+ return true;
+}
+
+#pragma mark -
+
+Audio32::Audio32(ResourceManager *resMan) :
+ _resMan(resMan),
+ _mixer(g_system->getMixer()),
+ _handle(),
+ _mutex(),
+
+ _numActiveChannels(0),
+ _inAudioThread(false),
+
+ _globalSampleRate(44100),
+ _maxAllowedSampleRate(44100),
+ _globalBitDepth(16),
+ _maxAllowedBitDepth(16),
+ _globalNumOutputChannels(2),
+ _maxAllowedOutputChannels(2),
+ _preload(0),
+
+ _robotAudioPaused(false),
+
+ _pausedAtTick(0),
+ _startedAtTick(0),
+
+ _attenuatedMixing(true),
+
+ _monitoredChannelIndex(-1),
+ _monitoredBuffer(nullptr),
+ _monitoredBufferSize(0),
+ _numMonitoredSamples(0) {
+
+ if (getSciVersion() < SCI_VERSION_3) {
+ _channels.resize(5);
+ } else {
+ _channels.resize(8);
+ }
+
+ _useModifiedAttenuation = false;
+ if (getSciVersion() == SCI_VERSION_2_1_MIDDLE) {
+ switch (g_sci->getGameId()) {
+ case GID_MOTHERGOOSEHIRES:
+ case GID_PQ4:
+ case GID_QFG4:
+ case GID_SQ6:
+ _useModifiedAttenuation = true;
+ default:
+ break;
+ }
+ } else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) {
+ // KQ7 1.51 uses the non-standard attenuation, but 2.00b
+ // does not, which is strange.
+ _useModifiedAttenuation = true;
+ }
+
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+}
+
+Audio32::~Audio32() {
+ stop(kAllChannels);
+ _mixer->stopHandle(_handle);
+ free(_monitoredBuffer);
+}
+
+#pragma mark -
+#pragma mark AudioStream implementation
+
+int Audio32::writeAudioInternal(Audio::RewindableAudioStream *const sourceStream, Audio::RateConverter *const converter, Audio::st_sample_t *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume, const bool loop) {
+ int samplesToRead = numSamples;
+
+ // The parent rate converter will request N * 2
+ // samples from this `readBuffer` call, because
+ // we tell it that we send stereo output, but
+ // the source stream we're mixing in may be
+ // mono, in which case we need to request half
+ // as many samples from the mono stream and let
+ // the converter double them for stereo output
+ if (!sourceStream->isStereo()) {
+ samplesToRead >>= 1;
+ }
+
+ int samplesWritten = 0;
+
+ do {
+ if (loop && sourceStream->endOfStream()) {
+ sourceStream->rewind();
+ }
+
+ const int loopSamplesWritten = converter->flow(*sourceStream, targetBuffer, samplesToRead, leftVolume, rightVolume);
+
+ if (loopSamplesWritten == 0) {
+ break;
+ }
+
+ samplesToRead -= loopSamplesWritten;
+ samplesWritten += loopSamplesWritten;
+ targetBuffer += loopSamplesWritten << 1;
+ } while (loop && samplesToRead > 0);
+
+ if (!sourceStream->isStereo()) {
+ samplesWritten <<= 1;
+ }
+
+ return samplesWritten;
+}
+
+// In earlier versions of SCI32 engine, audio mixing is
+// split into three different functions.
+//
+// The first function is called from the main game thread in
+// AsyncEventCheck; later versions of SSCI also call it when
+// getting the playback position. This function is
+// responsible for cleaning up finished channels and
+// filling active channel buffers with decompressed audio
+// matching the hardware output audio format so they can
+// just be copied into the main DAC buffer directly later.
+//
+// The second function is called by the audio hardware when
+// the DAC buffer needs to be filled, and by `play` when
+// there is only one active sample (so it can just blow away
+// whatever was already in the DAC buffer). It merges all
+// active channels into the DAC buffer and then updates the
+// offset into the DAC buffer.
+//
+// Finally, a third function is called by the second
+// function, and it actually puts data into the DAC buffer,
+// performing volume, distortion, and balance adjustments.
+//
+// Since we only have one callback from the audio thread,
+// and should be able to do all audio processing in
+// real time, and we have streams, and we do not need to
+// completely fill the audio buffer, the functionality of
+// all these original functions is combined here and
+// simplified.
+int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
+ Common::StackLock lock(_mutex);
+
+ if (_pausedAtTick != 0 || _numActiveChannels == 0) {
+ return 0;
+ }
+
+ // ResourceManager is not thread-safe so we need to
+ // avoid calling into it from the audio thread, but at
+ // the same time we need to be able to clear out any
+ // finished channels on a regular basis
+ _inAudioThread = true;
+
+ freeUnusedChannels();
+
+ // The caller of `readBuffer` is a rate converter,
+ // which reuses (without clearing) an intermediate
+ // buffer, so we need to zero the intermediate buffer
+ // to prevent mixing into audio data from the last
+ // callback.
+ memset(buffer, 0, numSamples * sizeof(Audio::st_sample_t));
+
+ // This emulates the attenuated mixing mode of SSCI
+ // engine, which reduces the volume of the target
+ // buffer when each new channel is mixed in.
+ // Instead of manipulating the content of the target
+ // buffer when mixing (which would either require
+ // modification of RateConverter or an expensive second
+ // pass against the entire target buffer), we just
+ // scale the volume for each channel in advance, with
+ // the earliest (lowest) channel having the highest
+ // amount of attenuation (lowest volume).
+ uint8 attenuationAmount;
+ uint8 attenuationStepAmount;
+ if (_useModifiedAttenuation) {
+ // channel | divisor
+ // 0 | 0 (>> 0)
+ // 1 | 4 (>> 2)
+ // 2 | 8...
+ attenuationAmount = _numActiveChannels * 2;
+ attenuationStepAmount = 2;
+ } else {
+ // channel | divisor
+ // 0 | 2 (>> 1)
+ // 1 | 4 (>> 2)
+ // 2 | 6...
+ if (_monitoredChannelIndex == -1 && _numActiveChannels > 1) {
+ attenuationAmount = _numActiveChannels + 1;
+ attenuationStepAmount = 1;
+ } else {
+ attenuationAmount = 0;
+ attenuationStepAmount = 0;
+ }
+ }
+
+ int maxSamplesWritten = 0;
+
+ for (int16 channelIndex = 0; channelIndex < _numActiveChannels; ++channelIndex) {
+ attenuationAmount -= attenuationStepAmount;
+
+ const AudioChannel &channel = getChannel(channelIndex);
+
+ if (channel.pausedAtTick || (channel.robot && _robotAudioPaused)) {
+ continue;
+ }
+
+ // Channel finished fading and had the
+ // stopChannelOnFade flag set, so no longer exists
+ if (channel.fadeStartTick && processFade(channelIndex)) {
+ --channelIndex;
+ continue;
+ }
+
+ if (channel.robot) {
+ // TODO: Robot audio into output buffer
+ continue;
+ }
+
+ if (channel.vmd) {
+ // TODO: VMD audio into output buffer
+ continue;
+ }
+
+ Audio::st_volume_t leftVolume, rightVolume;
+
+ if (channel.pan == -1 || !isStereo()) {
+ leftVolume = rightVolume = channel.volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume;
+ } else {
+ // TODO: This should match the SCI3 algorithm,
+ // which seems to halve the volume of each
+ // channel when centered; is this intended?
+ leftVolume = channel.volume * (100 - channel.pan) / 100 * Audio::Mixer::kMaxChannelVolume / kMaxVolume;
+ rightVolume = channel.volume * channel.pan / 100 * Audio::Mixer::kMaxChannelVolume / kMaxVolume;
+ }
+
+ if (_monitoredChannelIndex == -1 && _attenuatedMixing) {
+ leftVolume >>= attenuationAmount;
+ rightVolume >>= attenuationAmount;
+ }
+
+ if (channelIndex == _monitoredChannelIndex) {
+ const size_t bufferSize = numSamples * sizeof(Audio::st_sample_t);
+ if (_monitoredBufferSize < bufferSize) {
+ _monitoredBuffer = (Audio::st_sample_t *)realloc(_monitoredBuffer, bufferSize);
+ _monitoredBufferSize = bufferSize;
+ }
+
+ memset(_monitoredBuffer, 0, _monitoredBufferSize);
+
+ _numMonitoredSamples = writeAudioInternal(channel.stream, channel.converter, _monitoredBuffer, numSamples, leftVolume, rightVolume, channel.loop);
+
+ Audio::st_sample_t *sourceBuffer = _monitoredBuffer;
+ Audio::st_sample_t *targetBuffer = buffer;
+ const Audio::st_sample_t *const end = _monitoredBuffer + _numMonitoredSamples;
+ while (sourceBuffer != end) {
+ Audio::clampedAdd(*targetBuffer++, *sourceBuffer++);
+ }
+
+ if (_numMonitoredSamples > maxSamplesWritten) {
+ maxSamplesWritten = _numMonitoredSamples;
+ }
+ } else if (!channel.stream->endOfStream() || channel.loop) {
+ if (_monitoredChannelIndex != -1) {
+ // Audio that is not on the monitored channel is silent
+ // when the monitored channel is active, but the stream still
+ // needs to be read in order to ensure that sound effects sync
+ // up once the monitored channel is turned off. The easiest
+ // way to guarantee this is to just do the normal channel read,
+ // but set the channel volume to zero so nothing is mixed in
+ leftVolume = rightVolume = 0;
+ }
+
+ const int channelSamplesWritten = writeAudioInternal(channel.stream, channel.converter, buffer, numSamples, leftVolume, rightVolume, channel.loop);
+ if (channelSamplesWritten > maxSamplesWritten) {
+ maxSamplesWritten = channelSamplesWritten;
+ }
+ }
+ }
+
+ _inAudioThread = false;
+
+ return maxSamplesWritten;
+}
+
+#pragma mark -
+#pragma mark Channel management
+
+int16 Audio32::findChannelByArgs(int argc, const reg_t *argv, const int startIndex, const reg_t soundNode) const {
+ // NOTE: argc/argv are already reduced by one in our engine because
+ // this call is always made from a subop, so no reduction for the
+ // subop is made in this function. SSCI takes extra steps to skip
+ // the subop argument.
+
+ argc -= startIndex;
+ if (argc <= 0) {
+ return kAllChannels;
+ }
+
+ Common::StackLock lock(_mutex);
+
+ if (_numActiveChannels == 0) {
+ return kNoExistingChannel;
+ }
+
+ ResourceId searchId;
+
+ if (argc < 5) {
+ searchId = ResourceId(kResourceTypeAudio, argv[startIndex].toUint16());
+ } else {
+ searchId = ResourceId(
+ kResourceTypeAudio36,
+ argv[startIndex].toUint16(),
+ argv[startIndex + 1].toUint16(),
+ argv[startIndex + 2].toUint16(),
+ argv[startIndex + 3].toUint16(),
+ argv[startIndex + 4].toUint16()
+ );
+ }
+
+ return findChannelById(searchId, soundNode);
+}
+
+int16 Audio32::findChannelById(const ResourceId resourceId, const reg_t soundNode) const {
+ Common::StackLock lock(_mutex);
+
+ if (_numActiveChannels == 0) {
+ return kNoExistingChannel;
+ }
+
+ if (resourceId.getType() == kResourceTypeAudio) {
+ for (int16 i = 0; i < _numActiveChannels; ++i) {
+ const AudioChannel channel = _channels[i];
+ if (
+ channel.id == resourceId &&
+ (soundNode.isNull() || soundNode == channel.soundNode)
+ ) {
+ return i;
+ }
+ }
+ } else if (resourceId.getType() == kResourceTypeAudio36) {
+ for (int16 i = 0; i < _numActiveChannels; ++i) {
+ const AudioChannel &candidate = getChannel(i);
+ if (!candidate.robot && candidate.id == resourceId) {
+ return i;
+ }
+ }
+ } else {
+ error("Audio32::findChannelById: Unknown resource type %d", resourceId.getType());
+ }
+
+ return kNoExistingChannel;
+}
+
+void Audio32::freeUnusedChannels() {
+ Common::StackLock lock(_mutex);
+ for (int channelIndex = 0; channelIndex < _numActiveChannels; ++channelIndex) {
+ const AudioChannel &channel = getChannel(channelIndex);
+ if (channel.stream->endOfStream()) {
+ if (channel.loop) {
+ channel.stream->rewind();
+ } else {
+ stop(channelIndex--);
+ }
+ }
+ }
+
+ if (!_inAudioThread) {
+ unlockResources();
+ }
+}
+
+void Audio32::freeChannel(const int16 channelIndex) {
+ // The original engine did this:
+ // 1. Unlock memory-cached resource, if one existed
+ // 2. Close patched audio file descriptor, if one existed
+ // 3. Free decompression memory buffer, if one existed
+ // 4. Clear monitored memory buffer, if one existed
+ Common::StackLock lock(_mutex);
+ AudioChannel &channel = getChannel(channelIndex);
+
+ // We cannot unlock resources from the audio thread
+ // because ResourceManager is not thread-safe; instead,
+ // we just record that the resource needs unlocking and
+ // unlock it whenever we are on the main thread again
+ if (_inAudioThread) {
+ _resourcesToUnlock.push_back(channel.resource);
+ } else {
+ _resMan->unlockResource(channel.resource);
+ }
+
+ channel.resource = nullptr;
+ delete channel.stream;
+ channel.stream = nullptr;
+ delete channel.resourceStream;
+ channel.resourceStream = nullptr;
+ delete channel.converter;
+ channel.converter = nullptr;
+
+ if (_monitoredChannelIndex == channelIndex) {
+ _monitoredChannelIndex = -1;
+ }
+}
+
+void Audio32::unlockResources() {
+ Common::StackLock lock(_mutex);
+ assert(!_inAudioThread);
+
+ for (UnlockList::const_iterator it = _resourcesToUnlock.begin(); it != _resourcesToUnlock.end(); ++it) {
+ _resMan->unlockResource(*it);
+ }
+ _resourcesToUnlock.clear();
+}
+
+#pragma mark -
+#pragma mark Script compatibility
+
+void Audio32::setSampleRate(uint16 rate) {
+ if (rate > _maxAllowedSampleRate) {
+ rate = _maxAllowedSampleRate;
+ }
+
+ _globalSampleRate = rate;
+}
+
+void Audio32::setBitDepth(uint8 depth) {
+ if (depth > _maxAllowedBitDepth) {
+ depth = _maxAllowedBitDepth;
+ }
+
+ _globalBitDepth = depth;
+}
+
+void Audio32::setNumOutputChannels(int16 numChannels) {
+ if (numChannels > _maxAllowedOutputChannels) {
+ numChannels = _maxAllowedOutputChannels;
+ }
+
+ _globalNumOutputChannels = numChannels;
+}
+
+#pragma mark -
+#pragma mark Playback
+
+uint16 Audio32::play(int16 channelIndex, const ResourceId resourceId, const bool autoPlay, const bool loop, const int16 volume, const reg_t soundNode, const bool monitor) {
+ Common::StackLock lock(_mutex);
+
+ freeUnusedChannels();
+
+ if (channelIndex != kNoExistingChannel) {
+ AudioChannel &channel = getChannel(channelIndex);
+
+ if (channel.pausedAtTick) {
+ resume(channelIndex);
+ return MIN(65534, 1 + channel.stream->getLength().msecs() * 60 / 1000);
+ }
+
+ warning("Tried to resume channel %s that was not paused", channel.id.toString().c_str());
+ return MIN(65534, 1 + channel.stream->getLength().msecs() * 60 / 1000);
+ }
+
+ if (_numActiveChannels == _channels.size()) {
+ warning("Audio mixer is full when trying to play %s", resourceId.toString().c_str());
+ return 0;
+ }
+
+ // NOTE: SCI engine itself normally searches in this order:
+ //
+ // For Audio36:
+ //
+ // 1. First, request a FD using Audio36 name and use it as the
+ // source FD for reading the audio resource data.
+ // 2a. If the returned FD is -1, or equals the audio map, or
+ // equals the audio bundle, try to get the offset of the
+ // data from the audio map, using the Audio36 name.
+ //
+ // If the returned offset is -1, this is not a valid resource;
+ // return 0. Otherwise, set the read offset for the FD to the
+ // returned offset.
+ // 2b. Otherwise, use the FD as-is (it is a patch file), with zero
+ // offset, and record it separately so it can be closed later.
+ //
+ // For plain audio:
+ //
+ // 1. First, request an Audio resource from the resource cache. If
+ // one does not exist, make the same request for a Wave resource.
+ // 2a. If an audio resource was discovered, record its memory ID
+ // and clear the streaming FD
+ // 2b. Otherwise, request an Audio FD. If one does not exist, make
+ // the same request for a Wave FD. If neither exist, this is not
+ // a valid resource; return 0. Otherwise, use the returned FD as
+ // the streaming ID and set the memory ID to null.
+ //
+ // Once these steps are complete, the audio engine either has a file
+ // descriptor + offset that it can use to read streamed audio, or it
+ // has a memory ID that it can use to read cached audio.
+ //
+ // Here in ScummVM we just ask the resource manager to give us the
+ // resource and we get a seekable stream.
+
+ // TODO: This should be fixed to use streaming, which means
+ // fixing the resource manager to allow streaming, which means
+ // probably rewriting a bunch of the resource manager.
+ Resource *resource = _resMan->findResource(resourceId, true);
+ if (resource == nullptr) {
+ return 0;
+ }
+
+ channelIndex = _numActiveChannels++;
+
+ AudioChannel &channel = getChannel(channelIndex);
+ channel.id = resourceId;
+ channel.resource = resource;
+ channel.loop = loop;
+ channel.robot = false;
+ channel.vmd = false;
+ channel.fadeStartTick = 0;
+ channel.soundNode = soundNode;
+ channel.volume = volume < 0 || volume > kMaxVolume ? (int)kMaxVolume : volume;
+ // TODO: SCI3 introduces stereo audio
+ channel.pan = -1;
+
+ if (monitor) {
+ _monitoredChannelIndex = channelIndex;
+ }
+
+ Common::MemoryReadStream headerStream(resource->_header, resource->_headerSize, DisposeAfterUse::NO);
+ Common::SeekableReadStream *dataStream = channel.resourceStream = resource->makeStream();
+
+ if (detectSolAudio(headerStream)) {
+ channel.stream = makeSOLStream(&headerStream, dataStream, DisposeAfterUse::NO);
+ } else if (detectWaveAudio(*dataStream)) {
+ channel.stream = Audio::makeWAVStream(dataStream, DisposeAfterUse::NO);
+ } else {
+ byte flags = Audio::FLAG_LITTLE_ENDIAN;
+ if (_globalBitDepth == 16) {
+ flags |= Audio::FLAG_16BITS;
+ } else {
+ flags |= Audio::FLAG_UNSIGNED;
+ }
+
+ if (_globalNumOutputChannels == 2) {
+ flags |= Audio::FLAG_STEREO;
+ }
+
+ channel.stream = Audio::makeRawStream(dataStream, _globalSampleRate, flags, DisposeAfterUse::NO);
+ }
+
+ channel.converter = Audio::makeRateConverter(channel.stream->getRate(), getRate(), channel.stream->isStereo(), false);
+
+ // NOTE: SCI engine sets up a decompression buffer here for the audio
+ // stream, plus writes information about the sample to the channel to
+ // convert to the correct hardware output format, and allocates the
+ // monitoring buffer to match the bitrate/samplerate/channels of the
+ // original stream. We do not need to do any of these things since we
+ // use audio streams, and allocate and fill the monitoring buffer
+ // when reading audio data from the stream.
+
+ channel.duration = /* round up */ 1 + (channel.stream->getLength().msecs() * 60 / 1000);
+
+ const uint32 now = g_sci->getTickCount();
+ channel.pausedAtTick = autoPlay ? 0 : now;
+ channel.startedAtTick = now;
+
+ if (_numActiveChannels == 1) {
+ _startedAtTick = now;
+ }
+
+ return channel.duration;
+}
+
+bool Audio32::resume(const int16 channelIndex) {
+ if (channelIndex == kNoExistingChannel) {
+ return false;
+ }
+
+ Common::StackLock lock(_mutex);
+ const uint32 now = g_sci->getTickCount();
+
+ if (channelIndex == kAllChannels) {
+ // Global pause in SSCI is an extra layer over
+ // individual channel pauses, so only unpause channels
+ // if there was not a global pause in place
+ if (_pausedAtTick == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < _numActiveChannels; ++i) {
+ AudioChannel &channel = getChannel(i);
+ if (!channel.pausedAtTick) {
+ channel.startedAtTick += now - _pausedAtTick;
+ }
+ }
+
+ _startedAtTick += now - _pausedAtTick;
+ _pausedAtTick = 0;
+ return true;
+ } else if (channelIndex == kRobotChannel) {
+ for (int i = 0; i < _numActiveChannels; ++i) {
+ AudioChannel &channel = getChannel(i);
+ if (channel.robot) {
+ channel.startedAtTick += now - channel.pausedAtTick;
+ channel.pausedAtTick = 0;
+ // TODO: Robot
+ // StartRobot();
+ return true;
+ }
+ }
+ } else {
+ AudioChannel &channel = getChannel(channelIndex);
+ if (channel.pausedAtTick) {
+ channel.startedAtTick += now - channel.pausedAtTick;
+ channel.pausedAtTick = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Audio32::pause(const int16 channelIndex) {
+ if (channelIndex == kNoExistingChannel) {
+ return false;
+ }
+
+ Common::StackLock lock(_mutex);
+ const uint32 now = g_sci->getTickCount();
+ bool didPause = false;
+
+ if (channelIndex == kAllChannels) {
+ if (_pausedAtTick == 0) {
+ _pausedAtTick = now;
+ didPause = true;
+ }
+ } else if (channelIndex == kRobotChannel) {
+ _robotAudioPaused = true;
+ for (int16 i = 0; i < _numActiveChannels; ++i) {
+ AudioChannel &channel = getChannel(i);
+ if (channel.robot) {
+ channel.pausedAtTick = now;
+ }
+ }
+
+ // NOTE: The actual engine returns false here regardless of whether
+ // or not channels were paused
+ } else {
+ AudioChannel &channel = getChannel(channelIndex);
+
+ if (channel.pausedAtTick == 0) {
+ channel.pausedAtTick = now;
+ didPause = true;
+ }
+ }
+
+ return didPause;
+}
+
+int16 Audio32::stop(const int16 channelIndex) {
+ Common::StackLock lock(_mutex);
+ const int16 oldNumChannels = _numActiveChannels;
+
+ if (channelIndex == kNoExistingChannel || oldNumChannels == 0) {
+ return 0;
+ }
+
+ if (channelIndex == kAllChannels) {
+ for (int i = 0; i < oldNumChannels; ++i) {
+ freeChannel(i);
+ }
+ _numActiveChannels = 0;
+ } else {
+ freeChannel(channelIndex);
+ --_numActiveChannels;
+ for (int i = channelIndex; i < oldNumChannels - 1; ++i) {
+ _channels[i] = _channels[i + 1];
+ if (i + 1 == _monitoredChannelIndex) {
+ _monitoredChannelIndex = i;
+ }
+ }
+ }
+
+ // NOTE: SSCI stops the DSP interrupt and frees the
+ // global decompression buffer here if there are no
+ // more active channels
+
+ return oldNumChannels;
+}
+
+int16 Audio32::getPosition(const int16 channelIndex) const {
+ Common::StackLock lock(_mutex);
+ if (channelIndex == kNoExistingChannel || _numActiveChannels == 0) {
+ return -1;
+ }
+
+ // NOTE: SSCI treats this as an unsigned short except for
+ // when the value is 65535, then it treats it as signed
+ int position = -1;
+ const uint32 now = g_sci->getTickCount();
+
+ // NOTE: The original engine also queried the audio driver to see whether
+ // it thought that there was audio playback occurring via driver opcode 9
+ if (channelIndex == kAllChannels) {
+ if (_pausedAtTick) {
+ position = _pausedAtTick - _startedAtTick;
+ } else {
+ position = now - _startedAtTick;
+ }
+ } else {
+ const AudioChannel &channel = getChannel(channelIndex);
+
+ if (channel.pausedAtTick) {
+ position = channel.pausedAtTick - channel.startedAtTick;
+ } else if (_pausedAtTick) {
+ position = _pausedAtTick - channel.startedAtTick;
+ } else {
+ position = now - channel.startedAtTick;
+ }
+ }
+
+ return MIN(position, 65534);
+}
+
+void Audio32::setLoop(const int16 channelIndex, const bool loop) {
+ Common::StackLock lock(_mutex);
+
+ if (channelIndex < 0 || channelIndex >= _numActiveChannels) {
+ return;
+ }
+
+ AudioChannel &channel = getChannel(channelIndex);
+ channel.loop = loop;
+}
+
+reg_t Audio32::kernelPlay(const bool autoPlay, const int argc, const reg_t *const argv) {
+ if (argc == 0) {
+ return make_reg(0, _numActiveChannels);
+ }
+
+ const int16 channelIndex = findChannelByArgs(argc, argv, 0, NULL_REG);
+ ResourceId resourceId;
+ bool loop;
+ int16 volume;
+ bool monitor = false;
+ reg_t soundNode = NULL_REG;
+
+ if (argc >= 5) {
+ resourceId = ResourceId(kResourceTypeAudio36, argv[0].toUint16(), argv[1].toUint16(), argv[2].toUint16(), argv[3].toUint16(), argv[4].toUint16());
+
+ if (argc < 6 || argv[5].toSint16() == 1) {
+ loop = false;
+ } else {
+ // NOTE: Uses -1 for infinite loop. Presumably the
+ // engine was supposed to allow counter loops at one
+ // point, but ended up only using loop as a boolean.
+ loop = (bool)argv[5].toSint16();
+ }
+
+ if (argc < 7 || argv[6].toSint16() < 0 || argv[6].toSint16() > Audio32::kMaxVolume) {
+ volume = Audio32::kMaxVolume;
+
+ if (argc >= 7) {
+ monitor = true;
+ }
+ } else {
+ volume = argv[6].toSint16();
+ }
+ } else {
+ resourceId = ResourceId(kResourceTypeAudio, argv[0].toUint16());
+
+ if (argc < 2 || argv[1].toSint16() == 1) {
+ loop = false;
+ } else {
+ loop = (bool)argv[1].toSint16();
+ }
+
+ // TODO: SCI3 uses the 0x80 bit as a flag to
+ // indicate "priority channel", but the volume is clamped
+ // in this call to 0x7F so that flag never makes it into
+ // the audio subsystem
+ if (argc < 3 || argv[2].toSint16() < 0 || argv[2].toSint16() > Audio32::kMaxVolume) {
+ volume = Audio32::kMaxVolume;
+
+ if (argc >= 3) {
+ monitor = true;
+ }
+ } else {
+ volume = argv[2].toSint16();
+ }
+
+ soundNode = argc == 4 ? argv[3] : NULL_REG;
+ }
+
+ return make_reg(0, play(channelIndex, resourceId, autoPlay, loop, volume, soundNode, monitor));
+}
+
+#pragma mark -
+#pragma mark Effects
+
+int16 Audio32::getVolume(const int16 channelIndex) const {
+ if (channelIndex < 0 || channelIndex >= _numActiveChannels) {
+ return _mixer->getChannelVolume(_handle) * kMaxVolume / Audio::Mixer::kMaxChannelVolume;
+ }
+
+ Common::StackLock lock(_mutex);
+ return getChannel(channelIndex).volume;
+}
+
+void Audio32::setVolume(const int16 channelIndex, int16 volume) {
+ volume = MIN((int16)kMaxVolume, volume);
+ if (channelIndex == kAllChannels) {
+ ConfMan.setInt("sfx_volume", volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume);
+ ConfMan.setInt("speech_volume", volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume);
+ _mixer->setChannelVolume(_handle, volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume);
+ g_engine->syncSoundSettings();
+ } else if (channelIndex != kNoExistingChannel) {
+ Common::StackLock lock(_mutex);
+ getChannel(channelIndex).volume = volume;
+ }
+}
+
+bool Audio32::fadeChannel(const int16 channelIndex, const int16 targetVolume, const int16 speed, const int16 steps, const bool stopAfterFade) {
+ Common::StackLock lock(_mutex);
+
+ if (channelIndex < 0 || channelIndex >= _numActiveChannels) {
+ return false;
+ }
+
+ AudioChannel &channel = getChannel(channelIndex);
+
+ if (channel.id.getType() != kResourceTypeAudio || channel.volume == targetVolume) {
+ return false;
+ }
+
+ if (steps && speed) {
+ channel.fadeStartTick = g_sci->getTickCount();
+ channel.fadeStartVolume = channel.volume;
+ channel.fadeTargetVolume = targetVolume;
+ channel.fadeDuration = speed * steps;
+ channel.stopChannelOnFade = stopAfterFade;
+ } else {
+ setVolume(channelIndex, targetVolume);
+ }
+
+ return true;
+}
+
+bool Audio32::processFade(const int16 channelIndex) {
+ Common::StackLock lock(_mutex);
+ AudioChannel &channel = getChannel(channelIndex);
+
+ if (channel.fadeStartTick) {
+ const uint32 fadeElapsed = g_sci->getTickCount() - channel.fadeStartTick;
+ if (fadeElapsed > channel.fadeDuration) {
+ channel.fadeStartTick = 0;
+ if (channel.stopChannelOnFade) {
+ stop(channelIndex);
+ return true;
+ } else {
+ setVolume(channelIndex, channel.fadeTargetVolume);
+ }
+ return false;
+ }
+
+ int volume;
+ if (channel.fadeStartVolume > channel.fadeTargetVolume) {
+ volume = channel.fadeStartVolume - fadeElapsed * (channel.fadeStartVolume - channel.fadeTargetVolume) / channel.fadeDuration;
+ } else {
+ volume = channel.fadeStartVolume + fadeElapsed * (channel.fadeTargetVolume - channel.fadeStartVolume) / channel.fadeDuration;
+ }
+
+ setVolume(channelIndex, volume);
+ return false;
+ }
+
+ return false;
+}
+
+#pragma mark -
+#pragma mark Signal monitoring
+
+bool Audio32::hasSignal() const {
+ Common::StackLock lock(_mutex);
+
+ if (_monitoredChannelIndex == -1) {
+ return false;
+ }
+
+ const Audio::st_sample_t *buffer = _monitoredBuffer;
+ const Audio::st_sample_t *const end = _monitoredBuffer + _numMonitoredSamples;
+
+ while (buffer != end) {
+ const Audio::st_sample_t sample = *buffer++;
+ if (sample > 1280 || sample < -1280) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/sound/audio32.h b/engines/sci/sound/audio32.h
new file mode 100644
index 0000000000..b0c1ba1998
--- /dev/null
+++ b/engines/sci/sound/audio32.h
@@ -0,0 +1,589 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_AUDIO32_H
+#define SCI_AUDIO32_H
+#include "audio/audiostream.h" // for AudioStream, SeekableAudioStream (...
+#include "audio/mixer.h" // for Mixer, SoundHandle
+#include "audio/rate.h" // for Audio::st_volume_t, RateConverter
+#include "common/array.h" // for Array
+#include "common/mutex.h" // for StackLock, Mutex
+#include "common/scummsys.h" // for int16, uint8, uint32, uint16
+#include "engines/sci/resource.h" // for ResourceId
+#include "sci/engine/vm_types.h" // for reg_t, NULL_REG
+
+namespace Sci {
+
+/**
+ * An audio channel used by the software SCI mixer.
+ */
+struct AudioChannel {
+ /**
+ * The ID of the resource loaded into this channel.
+ */
+ ResourceId id;
+
+ /**
+ * The resource loaded into this channel.
+ */
+ Resource *resource;
+
+ /**
+ * Data stream containing the raw audio for the channel.
+ */
+ Common::SeekableReadStream *resourceStream;
+
+ /**
+ * The audio stream loaded into this channel.
+ * `SeekableAudioStream` is used here instead of
+ * `RewindableAudioStream` because
+ * `RewindableAudioStream` does not include the
+ * `getLength` function, which is needed to tell the
+ * game engine the duration of audio streams.
+ */
+ Audio::SeekableAudioStream *stream;
+
+ /**
+ * The converter used to transform and merge the input
+ * stream into the mixer's output buffer.
+ */
+ Audio::RateConverter *converter;
+
+ /**
+ * Duration of the channel, in ticks.
+ */
+ uint32 duration;
+
+ /**
+ * The tick when the channel was started.
+ */
+ uint32 startedAtTick;
+
+ /**
+ * The tick when the channel was paused.
+ */
+ uint32 pausedAtTick;
+
+ /**
+ * Whether or not the audio in this channel should loop
+ * infinitely.
+ */
+ bool loop;
+
+ /**
+ * The time, in ticks, that the channel fade began.
+ * If 0, the channel is not being faded.
+ */
+ uint32 fadeStartTick;
+
+ /**
+ * The start volume of a fade.
+ */
+ int fadeStartVolume;
+
+ /**
+ * The total length of the fade, in ticks.
+ */
+ uint32 fadeDuration;
+
+ /**
+ * The end volume of a fade.
+ */
+ int fadeTargetVolume;
+
+ /**
+ * Whether or not the channel should be stopped and
+ * freed when the fade is complete.
+ */
+ bool stopChannelOnFade;
+
+ /**
+ * Whether or not this channel contains a Robot
+ * audio block.
+ */
+ bool robot;
+
+ /**
+ * Whether or not this channel contains a VMD audio
+ * track.
+ */
+ bool vmd;
+
+ /**
+ * For digital sound effects, the related VM
+ * Sound::nodePtr object for the sound.
+ */
+ reg_t soundNode;
+
+ /**
+ * The playback volume, from 1 to 127 inclusive.
+ */
+ int volume;
+
+ /**
+ * The amount to pan to the right, from 0 to 100.
+ * 50 is centered, -1 is not panned.
+ */
+ int pan;
+};
+
+/**
+ * Special audio channel indexes used to select a channel
+ * for digital audio playback.
+ */
+enum AudioChannelIndex {
+ kRobotChannel = -3,
+ kNoExistingChannel = -2,
+ kAllChannels = -1
+};
+
+/**
+ * Audio32 acts as a permanent audio stream into the system
+ * mixer and provides digital audio services for the SCI32
+ * engine, since the system mixer does not support all the
+ * features of SCI.
+ */
+class Audio32 : public Audio::AudioStream {
+public:
+ Audio32(ResourceManager *resMan);
+ ~Audio32();
+
+private:
+ ResourceManager *_resMan;
+ Audio::Mixer *_mixer;
+ Audio::SoundHandle _handle;
+ Common::Mutex _mutex;
+
+ enum {
+ /**
+ * The maximum channel volume.
+ */
+ kMaxVolume = 127
+ };
+
+#pragma mark -
+#pragma mark AudioStream implementation
+public:
+ int readBuffer(Audio::st_sample_t *buffer, const int numSamples);
+ bool isStereo() const { return true; }
+ int getRate() const { return _mixer->getOutputRate(); }
+ bool endOfData() const { return _numActiveChannels == 0; }
+ bool endOfStream() const { return false; }
+
+private:
+ /**
+ * Mixes audio from the given source stream into the
+ * target buffer using the given rate converter.
+ */
+ int writeAudioInternal(Audio::RewindableAudioStream *const sourceStream, Audio::RateConverter *const converter, Audio::st_sample_t *targetBuffer, const int numSamples, const Audio::st_volume_t leftVolume, const Audio::st_volume_t rightVolume, const bool loop);
+
+#pragma mark -
+#pragma mark Channel management
+public:
+ /**
+ * Gets the number of currently active channels.
+ */
+ inline uint8 getNumActiveChannels() const {
+ Common::StackLock lock(_mutex);
+ return _numActiveChannels;
+ }
+
+ /**
+ * Finds a channel that is already configured for the
+ * given audio sample.
+ *
+ * @param startIndex The location of the audio resource
+ * information in the arguments list.
+ */
+ int16 findChannelByArgs(int argc, const reg_t *argv, const int startIndex, const reg_t soundNode) const;
+
+ /**
+ * Finds a channel that is already configured for the
+ * given audio sample.
+ */
+ int16 findChannelById(const ResourceId resourceId, const reg_t soundNode = NULL_REG) const;
+
+private:
+ typedef Common::Array<Resource *> UnlockList;
+
+ /**
+ * The audio channels.
+ */
+ Common::Array<AudioChannel> _channels;
+
+ /**
+ * The number of active audio channels in the mixer.
+ * Being active is not the same as playing; active
+ * channels may be paused.
+ */
+ uint8 _numActiveChannels;
+
+ /**
+ * Whether or not we are in the audio thread.
+ *
+ * This flag is used instead of passing a parameter to
+ * `freeUnusedChannels` because a parameter would
+ * require forwarding through the public method `stop`,
+ * and there is not currently any reason for this
+ * implementation detail to be exposed.
+ */
+ bool _inAudioThread;
+
+ /**
+ * The list of resources from freed channels that need
+ * to be unlocked from the main thread.
+ */
+ UnlockList _resourcesToUnlock;
+
+ /**
+ * Gets the audio channel at the given index.
+ */
+ inline AudioChannel &getChannel(const int16 channelIndex) {
+ Common::StackLock lock(_mutex);
+ assert(channelIndex >= 0 && channelIndex < _numActiveChannels);
+ return _channels[channelIndex];
+ }
+
+ /**
+ * Gets the audio channel at the given index.
+ */
+ inline const AudioChannel &getChannel(const int16 channelIndex) const {
+ Common::StackLock lock(_mutex);
+ assert(channelIndex >= 0 && channelIndex < _numActiveChannels);
+ return _channels[channelIndex];
+ }
+
+ /**
+ * Frees all non-looping channels that have reached the
+ * end of their stream.
+ */
+ void freeUnusedChannels();
+
+ /**
+ * Frees resources allocated to the given channel.
+ */
+ void freeChannel(const int16 channelIndex);
+
+ /**
+ * Unlocks all resources that were freed by the audio
+ * thread.
+ */
+ void unlockResources();
+
+#pragma mark -
+#pragma mark Script compatibility
+public:
+ /**
+ * Gets the (fake) sample rate of the hardware DAC.
+ * For script compatibility only.
+ */
+ inline uint16 getSampleRate() const {
+ return _globalSampleRate;
+ }
+
+ /**
+ * Sets the (fake) sample rate of the hardware DAC.
+ * For script compatibility only.
+ */
+ void setSampleRate(uint16 rate);
+
+ /**
+ * Gets the (fake) bit depth of the hardware DAC.
+ * For script compatibility only.
+ */
+ inline uint8 getBitDepth() const {
+ return _globalBitDepth;
+ }
+
+ /**
+ * Sets the (fake) sample rate of the hardware DAC.
+ * For script compatibility only.
+ */
+ void setBitDepth(uint8 depth);
+
+ /**
+ * Gets the (fake) number of output (speaker) channels
+ * of the hardware DAC. For script compatibility only.
+ */
+ inline uint8 getNumOutputChannels() const {
+ return _globalNumOutputChannels;
+ }
+
+ /**
+ * Sets the (fake) number of output (speaker) channels
+ * of the hardware DAC. For script compatibility only.
+ */
+ void setNumOutputChannels(int16 numChannels);
+
+ /**
+ * Gets the (fake) number of preloaded channels.
+ * For script compatibility only.
+ */
+ inline uint8 getPreload() const {
+ return _preload;
+ }
+
+ /**
+ * Sets the (fake) number of preloaded channels.
+ * For script compatibility only.
+ */
+ inline void setPreload(uint8 preload) {
+ _preload = preload;
+ }
+
+private:
+ /**
+ * The hardware DAC sample rate. Stored only for script
+ * compatibility.
+ */
+ uint16 _globalSampleRate;
+
+ /**
+ * The maximum allowed sample rate of the system mixer.
+ * Stored only for script compatibility.
+ */
+ uint16 _maxAllowedSampleRate;
+
+ /**
+ * The hardware DAC bit depth. Stored only for script
+ * compatibility.
+ */
+ uint8 _globalBitDepth;
+
+ /**
+ * The maximum allowed bit depth of the system mixer.
+ * Stored only for script compatibility.
+ */
+ uint8 _maxAllowedBitDepth;
+
+ /**
+ * The hardware DAC output (speaker) channel
+ * configuration. Stored only for script compatibility.
+ */
+ uint8 _globalNumOutputChannels;
+
+ /**
+ * The maximum allowed number of output (speaker)
+ * channels of the system mixer. Stored only for script
+ * compatibility.
+ */
+ uint8 _maxAllowedOutputChannels;
+
+ /**
+ * The number of audio channels that should have their
+ * data preloaded into memory instead of streaming from
+ * disk.
+ * 1 = all channels, 2 = 2nd active channel and above,
+ * etc.
+ * Stored only for script compatibility.
+ */
+ uint8 _preload;
+
+#pragma mark -
+#pragma mark Robot
+public:
+
+private:
+ /**
+ * When true, channels marked as robot audio will not be
+ * played.
+ */
+ bool _robotAudioPaused;
+
+#pragma mark -
+#pragma mark Playback
+public:
+ /**
+ * Starts or resumes playback of an audio channel.
+ */
+ uint16 play(int16 channelIndex, const ResourceId resourceId, const bool autoPlay, const bool loop, const int16 volume, const reg_t soundNode, const bool monitor);
+
+ /**
+ * Resumes playback of a paused audio channel, or of
+ * the entire audio player.
+ */
+ bool resume(const int16 channelIndex);
+ bool resume(const ResourceId resourceId, const reg_t soundNode = NULL_REG) {
+ Common::StackLock lock(_mutex);
+ return resume(findChannelById(resourceId, soundNode));
+ }
+
+ /**
+ * Pauses an audio channel, or the entire audio player.
+ */
+ bool pause(const int16 channelIndex);
+ bool pause(const ResourceId resourceId, const reg_t soundNode = NULL_REG) {
+ Common::StackLock lock(_mutex);
+ return pause(findChannelById(resourceId, soundNode));
+ }
+
+ /**
+ * Stops and unloads an audio channel, or the entire
+ * audio player.
+ */
+ int16 stop(const int16 channelIndex);
+ int16 stop(const ResourceId resourceId, const reg_t soundNode = NULL_REG) {
+ Common::StackLock lock(_mutex);
+ return stop(findChannelById(resourceId, soundNode));
+ }
+
+ /**
+ * Returns the playback position for the given channel
+ * number, in ticks.
+ */
+ int16 getPosition(const int16 channelIndex) const;
+ int16 getPosition(const ResourceId resourceId, const reg_t soundNode = NULL_REG) {
+ Common::StackLock lock(_mutex);
+ return getPosition(findChannelById(resourceId, soundNode));
+ }
+
+ /**
+ * Sets whether or not the given channel should loop.
+ */
+ void setLoop(const int16 channelIndex, const bool loop);
+ void setLoop(const ResourceId resourceId, const reg_t soundNode, const bool loop) {
+ Common::StackLock lock(_mutex);
+ setLoop(findChannelById(resourceId, soundNode), loop);
+ }
+
+ reg_t kernelPlay(const bool autoPlay, const int argc, const reg_t *const argv);
+
+private:
+ /**
+ * The tick when audio was globally paused.
+ */
+ uint32 _pausedAtTick;
+
+ /**
+ * The tick when audio was globally started.
+ */
+ uint32 _startedAtTick;
+
+#pragma mark -
+#pragma mark Effects
+public:
+ /**
+ * Gets the volume for a given channel. Passing
+ * `kAllChannels` will get the global volume.
+ */
+ int16 getVolume(const int16 channelIndex) const;
+ int16 getVolume(const ResourceId resourceId, const reg_t soundNode) const {
+ Common::StackLock lock(_mutex);
+ return getVolume(findChannelById(resourceId, soundNode));
+ }
+
+ /**
+ * Sets the volume of an audio channel. Passing
+ * `kAllChannels` will set the global volume.
+ */
+ void setVolume(const int16 channelIndex, int16 volume);
+ void setVolume(const ResourceId resourceId, const reg_t soundNode, const int16 volume) {
+ Common::StackLock lock(_mutex);
+ setVolume(findChannelById(resourceId, soundNode), volume);
+ }
+
+ /**
+ * Initiate an immediate fade of the given channel.
+ */
+ bool fadeChannel(const int16 channelIndex, const int16 targetVolume, const int16 speed, const int16 steps, const bool stopAfterFade);
+ bool fadeChannel(const ResourceId resourceId, const reg_t soundNode, const int16 targetVolume, const int16 speed, const int16 steps, const bool stopAfterFade) {
+ Common::StackLock lock(_mutex);
+ return fadeChannel(findChannelById(resourceId, soundNode), targetVolume, speed, steps, stopAfterFade);
+ }
+
+ /**
+ * Gets whether attenuated mixing mode is active.
+ */
+ inline bool getAttenuatedMixing() const {
+ return _attenuatedMixing;
+ }
+
+ /**
+ * Sets the attenuated mixing mode.
+ */
+ void setAttenuatedMixing(bool attenuated) {
+ Common::StackLock lock(_mutex);
+ _attenuatedMixing = attenuated;
+ }
+
+private:
+ /**
+ * If true, audio will be mixed by reducing the target
+ * buffer by half every time a new channel is mixed in.
+ * The final channel is not attenuated.
+ */
+ bool _attenuatedMixing;
+
+ /**
+ * When true, a modified attenuation algorithm is used
+ * (`A/4 + B`) instead of standard linear attenuation
+ * (`A/2 + B/2`).
+ */
+ bool _useModifiedAttenuation;
+
+ /**
+ * Processes an audio fade for the given channel.
+ *
+ * @returns true if the fade was completed and the
+ * channel was stopped.
+ */
+ bool processFade(const int16 channelIndex);
+
+#pragma mark -
+#pragma mark Signal monitoring
+public:
+ /**
+ * Returns whether the currently monitored audio channel
+ * contains any signal within the next audio frame.
+ */
+ bool hasSignal() const;
+
+private:
+ /**
+ * The index of the channel being monitored for signal,
+ * or -1 if no channel is monitored. When a channel is
+ * monitored, it also causes the engine to play only the
+ * monitored channel.
+ */
+ int16 _monitoredChannelIndex;
+
+ /**
+ * The data buffer holding decompressed audio data for
+ * the channel that will be monitored for an audio
+ * signal.
+ */
+ Audio::st_sample_t *_monitoredBuffer;
+
+ /**
+ * The size of the buffer, in bytes.
+ */
+ size_t _monitoredBufferSize;
+
+ /**
+ * The number of valid audio samples in the signal
+ * monitoring buffer.
+ */
+ int _numMonitoredSamples;
+};
+
+} // End of namespace Sci
+#endif
diff --git a/engines/sci/sound/decoders/sol.cpp b/engines/sci/sound/decoders/sol.cpp
new file mode 100644
index 0000000000..e445403120
--- /dev/null
+++ b/engines/sci/sound/decoders/sol.cpp
@@ -0,0 +1,273 @@
+/* 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.
+ *
+ */
+
+#include "audio/audiostream.h"
+#include "audio/decoders/raw.h"
+#include "common/substream.h"
+#include "common/util.h"
+#include "engines/sci/sci.h"
+#include "engines/sci/sound/decoders/sol.h"
+
+namespace Sci {
+
+// Note that the 16-bit version is also used in coktelvideo.cpp
+static const uint16 tableDPCM16[128] = {
+ 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
+ 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
+ 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
+ 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
+ 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
+ 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
+ 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
+ 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
+ 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
+ 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
+ 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
+ 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
+ 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
+};
+
+static const byte tableDPCM8[8] = { 0, 1, 2, 3, 6, 10, 15, 21 };
+
+/**
+ * Decompresses 16-bit DPCM compressed audio. Each byte read
+ * outputs one sample into the decompression buffer.
+ */
+static void deDPCM16(int16 *out, Common::ReadStream &audioStream, uint32 numBytes, int16 &sample) {
+ for (uint32 i = 0; i < numBytes; ++i) {
+ const uint8 delta = audioStream.readByte();
+ if (delta & 0x80) {
+ sample -= tableDPCM16[delta & 0x7f];
+ } else {
+ sample += tableDPCM16[delta];
+ }
+ sample = CLIP<int16>(sample, -32768, 32767);
+ *out++ = TO_LE_16(sample);
+ }
+}
+
+/**
+ * Decompresses one half of an 8-bit DPCM compressed audio
+ * byte.
+ */
+static void deDPCM8Nibble(int16 *out, uint8 &sample, uint8 delta) {
+ const uint8 lastSample = sample;
+ if (delta & 8) {
+ sample -= tableDPCM8[delta & 7];
+ } else {
+ sample += tableDPCM8[delta & 7];
+ }
+ sample = CLIP<byte>(sample, 0, 255);
+ *out = ((lastSample + sample) << 7) ^ 0x8000;
+}
+
+/**
+ * Decompresses 8-bit DPCM compressed audio. Each byte read
+ * outputs two samples into the decompression buffer.
+ */
+static void deDPCM8(int16 *out, Common::ReadStream &audioStream, uint32 numBytes, uint8 &sample) {
+ for (uint32 i = 0; i < numBytes; ++i) {
+ const uint8 delta = audioStream.readByte();
+ deDPCM8Nibble(out++, sample, delta >> 4);
+ deDPCM8Nibble(out++, sample, delta & 0xf);
+ }
+}
+
+# pragma mark -
+
+template<bool STEREO, bool S16BIT>
+SOLStream<STEREO, S16BIT>::SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const int32 dataOffset, const uint16 sampleRate, const int32 rawDataSize) :
+ _stream(stream, disposeAfterUse),
+ _dataOffset(dataOffset),
+ _sampleRate(sampleRate),
+ // SSCI aligns the size of SOL data to 32 bits
+ _rawDataSize(rawDataSize & ~3) {
+ // TODO: This is not valid for stereo SOL files, which
+ // have interleaved L/R compression so need to store the
+ // carried values for each channel separately. See
+ // 60900.aud from Lighthouse for an example stereo file
+ if (S16BIT) {
+ _dpcmCarry16 = 0;
+ } else {
+ _dpcmCarry8 = 0x80;
+ }
+
+ const uint8 compressionRatio = 2;
+ const uint8 numChannels = STEREO ? 2 : 1;
+ const uint8 bytesPerSample = S16BIT ? 2 : 1;
+ _length = Audio::Timestamp((_rawDataSize * compressionRatio * 1000) / (_sampleRate * numChannels * bytesPerSample), 60);
+ }
+
+template <bool STEREO, bool S16BIT>
+bool SOLStream<STEREO, S16BIT>::seek(const Audio::Timestamp &where) {
+ if (where != 0) {
+ // In order to seek in compressed SOL files, all
+ // previous bytes must be known since it uses
+ // differential compression. Therefore, only seeking
+ // to the beginning is supported now (SSCI does not
+ // offer seeking anyway)
+ return false;
+ }
+
+ if (S16BIT) {
+ _dpcmCarry16 = 0;
+ } else {
+ _dpcmCarry8 = 0x80;
+ }
+
+ return _stream->seek(_dataOffset, SEEK_SET);
+}
+
+template <bool STEREO, bool S16BIT>
+Audio::Timestamp SOLStream<STEREO, S16BIT>::getLength() const {
+ return _length;
+}
+
+template <bool STEREO, bool S16BIT>
+int SOLStream<STEREO, S16BIT>::readBuffer(int16 *buffer, const int numSamples) {
+ // Reading an odd number of 8-bit samples will result in a loss of samples
+ // since one byte represents two samples and we do not store the second
+ // nibble in this case; it should never happen in reality
+ assert(S16BIT || (numSamples % 2) == 0);
+
+ const int samplesPerByte = S16BIT ? 1 : 2;
+
+ int32 bytesToRead = numSamples / samplesPerByte;
+ if (_stream->pos() + bytesToRead > _rawDataSize) {
+ bytesToRead = _rawDataSize - _stream->pos();
+ }
+
+ if (S16BIT) {
+ deDPCM16(buffer, *_stream, bytesToRead, _dpcmCarry16);
+ } else {
+ deDPCM8(buffer, *_stream, bytesToRead, _dpcmCarry8);
+ }
+
+ const int samplesRead = bytesToRead * samplesPerByte;
+ return samplesRead;
+}
+
+template <bool STEREO, bool S16BIT>
+bool SOLStream<STEREO, S16BIT>::isStereo() const {
+ return STEREO;
+}
+
+template <bool STEREO, bool S16BIT>
+int SOLStream<STEREO, S16BIT>::getRate() const {
+ return _sampleRate;
+}
+
+template <bool STEREO, bool S16BIT>
+bool SOLStream<STEREO, S16BIT>::endOfData() const {
+ return _stream->eos() || _stream->pos() >= _dataOffset + _rawDataSize;
+}
+
+template <bool STEREO, bool S16BIT>
+bool SOLStream<STEREO, S16BIT>::rewind() {
+ return seek(0);
+}
+
+Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
+
+ // TODO: Might not be necessary? Makes seeking work, but
+ // not sure if audio is ever actually seeked in SSCI.
+ const int32 initialPosition = stream->pos();
+
+ byte header[6];
+ if (stream->read(header, sizeof(header)) != sizeof(header)) {
+ return nullptr;
+ }
+
+ if (header[0] != 0x8d || READ_BE_UINT32(header + 2) != MKTAG('S', 'O', 'L', 0)) {
+ return nullptr;
+ }
+
+ const uint8 headerSize = header[1];
+ const uint16 sampleRate = stream->readUint16LE();
+ const byte flags = stream->readByte();
+ const uint32 dataSize = stream->readUint32LE();
+
+ if (flags & kCompressed) {
+ if (flags & kStereo && flags & k16Bit) {
+ return new SOLStream<true, true>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
+ } else if (flags & kStereo) {
+ return new SOLStream<true, false>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
+ } else if (flags & k16Bit) {
+ return new SOLStream<false, true>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
+ } else {
+ return new SOLStream<false, false>(new Common::SeekableSubReadStream(stream, initialPosition, initialPosition + dataSize, disposeAfterUse), disposeAfterUse, headerSize, sampleRate, dataSize);
+ }
+ }
+
+ byte rawFlags = Audio::FLAG_LITTLE_ENDIAN;
+ if (flags & k16Bit) {
+ rawFlags |= Audio::FLAG_16BITS;
+ } else {
+ rawFlags |= Audio::FLAG_UNSIGNED;
+ }
+
+ if (flags & kStereo) {
+ rawFlags |= Audio::FLAG_STEREO;
+ }
+
+ return Audio::makeRawStream(new Common::SeekableSubReadStream(stream, initialPosition + headerSize, initialPosition + headerSize + dataSize, disposeAfterUse), sampleRate, rawFlags, disposeAfterUse);
+}
+
+// TODO: This needs to be removed when resource manager is fixed
+// to not split audio into two parts
+Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *headerStream, Common::SeekableReadStream *dataStream, DisposeAfterUse::Flag disposeAfterUse) {
+
+ if (headerStream->readUint32BE() != MKTAG('S', 'O', 'L', 0)) {
+ return nullptr;
+ }
+
+ const uint16 sampleRate = headerStream->readUint16LE();
+ const byte flags = headerStream->readByte();
+ const int32 dataSize = headerStream->readSint32LE();
+
+ if (flags & kCompressed) {
+ if (flags & kStereo && flags & k16Bit) {
+ return new SOLStream<true, true>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+ } else if (flags & kStereo) {
+ return new SOLStream<true, false>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+ } else if (flags & k16Bit) {
+ return new SOLStream<false, true>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+ } else {
+ return new SOLStream<false, false>(dataStream, disposeAfterUse, 0, sampleRate, dataSize);
+ }
+ }
+
+ byte rawFlags = Audio::FLAG_LITTLE_ENDIAN;
+ if (flags & k16Bit) {
+ rawFlags |= Audio::FLAG_16BITS;
+ } else {
+ rawFlags |= Audio::FLAG_UNSIGNED;
+ }
+
+ if (flags & kStereo) {
+ rawFlags |= Audio::FLAG_STEREO;
+ }
+
+ return Audio::makeRawStream(dataStream, sampleRate, rawFlags, disposeAfterUse);
+}
+
+}
diff --git a/engines/sci/sound/decoders/sol.h b/engines/sci/sound/decoders/sol.h
new file mode 100644
index 0000000000..1046d0b213
--- /dev/null
+++ b/engines/sci/sound/decoders/sol.h
@@ -0,0 +1,89 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_SOUND_DECODERS_SOL_H
+#define SCI_SOUND_DECODERS_SOL_H
+#include "audio/audiostream.h"
+#include "common/stream.h"
+
+namespace Sci {
+
+enum SOLFlags {
+ kCompressed = 1,
+ k16Bit = 4,
+ kStereo = 16
+};
+
+template <bool STEREO, bool S16BIT>
+class SOLStream : public Audio::SeekableAudioStream {
+private:
+ /**
+ * Read stream containing possibly-compressed SOL audio.
+ */
+ Common::DisposablePtr<Common::SeekableReadStream> _stream;
+
+ /**
+ * Start offset of the audio data in the read stream.
+ */
+ int32 _dataOffset;
+
+ /**
+ * Sample rate of audio data.
+ */
+ uint16 _sampleRate;
+
+ /**
+ * The raw (possibly-compressed) size of audio data in
+ * the stream.
+ */
+ int32 _rawDataSize;
+
+ /**
+ * The last sample from the previous DPCM decode.
+ */
+ union {
+ int16 _dpcmCarry16;
+ uint8 _dpcmCarry8;
+ };
+
+ /**
+ * The calculated length of the stream.
+ */
+ Audio::Timestamp _length;
+
+ virtual bool seek(const Audio::Timestamp &where) override;
+ virtual Audio::Timestamp getLength() const override;
+ virtual int readBuffer(int16 *buffer, const int numSamples) override;
+ virtual bool isStereo() const override;
+ virtual int getRate() const override;
+ virtual bool endOfData() const override;
+ virtual bool rewind() override;
+
+public:
+ SOLStream(Common::SeekableReadStream *stream, const DisposeAfterUse::Flag disposeAfterUse, const int32 dataOffset, const uint16 sampleRate, const int32 rawDataSize);
+};
+
+Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
+
+Audio::SeekableAudioStream *makeSOLStream(Common::SeekableReadStream *headerStream, Common::SeekableReadStream *dataStream, DisposeAfterUse::Flag disposeAfterUse);
+}
+#endif
diff --git a/engines/sci/sound/drivers/amigamac.cpp b/engines/sci/sound/drivers/amigamac.cpp
index 5ce49086ca..031fd32164 100644
--- a/engines/sci/sound/drivers/amigamac.cpp
+++ b/engines/sci/sound/drivers/amigamac.cpp
@@ -497,7 +497,7 @@ MidiDriver_AmigaMac::InstrumentSample *MidiDriver_AmigaMac::readInstrumentSCI0(C
}
instrument->samples = (int8 *) malloc(size + 1);
- if (file.read(instrument->samples, size) < (unsigned int)size) {
+ if (file.read(instrument->samples, size) < (uint32)size) {
warning("Amiga/Mac driver: failed to read instrument samples");
free(instrument->samples);
delete instrument;
@@ -773,6 +773,7 @@ bool MidiDriver_AmigaMac::loadInstrumentsSCI0(Common::File &file) {
if (id < 0 || id > 255) {
warning("Amiga/Mac driver: Error: instrument ID out of bounds");
+ delete instrument;
return false;
}
diff --git a/engines/sci/sound/drivers/midi.cpp b/engines/sci/sound/drivers/midi.cpp
index aa464cdc19..5e82e4a729 100644
--- a/engines/sci/sound/drivers/midi.cpp
+++ b/engines/sci/sound/drivers/midi.cpp
@@ -27,7 +27,7 @@
#include "common/memstream.h"
#include "common/system.h"
-#include "audio/fmopl.h"
+#include "audio/mididrv.h"
#include "sci/resource.h"
#include "sci/engine/features.h"
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 5a11ac386a..487d30e840 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -212,6 +212,13 @@ void SciMusic::clearPlayList() {
void SciMusic::pauseAll(bool pause) {
const MusicList::iterator end = _playList.end();
for (MusicList::iterator i = _playList.begin(); i != end; ++i) {
+#ifdef ENABLE_SCI32
+ // The entire DAC will have been paused by the caller;
+ // do not pause the individual samples too
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && (*i)->isSample) {
+ continue;
+ }
+#endif
soundToggle(*i, pause);
}
}
@@ -347,12 +354,14 @@ void SciMusic::soundInitSnd(MusicEntry *pSnd) {
pSnd->pStreamAud = Audio::makeRawStream(channelData + track->digitalSampleStart,
track->digitalSampleSize - track->digitalSampleStart - endPart,
track->digitalSampleRate, flags, DisposeAfterUse::NO);
+ assert(pSnd->pStreamAud);
delete pSnd->pLoopStream;
pSnd->pLoopStream = 0;
pSnd->soundType = Audio::Mixer::kSFXSoundType;
pSnd->hCurrentAud = Audio::SoundHandle();
pSnd->playBed = false;
pSnd->overridePriority = false;
+ pSnd->isSample = true;
} else {
// play MIDI track
Common::StackLock lock(_mutex);
@@ -472,7 +481,16 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
}
}
- if (pSnd->pStreamAud) {
+ if (pSnd->isSample) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ g_sci->_audio32->stop(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
+
+ g_sci->_audio32->play(kNoExistingChannel, ResourceId(kResourceTypeAudio, pSnd->resourceId), true, pSnd->loop != 0 && pSnd->loop != 1, pSnd->volume, pSnd->soundObj, false);
+
+ return;
+ } else
+#endif
if (!_pMixer->isSoundHandleActive(pSnd->hCurrentAud)) {
if ((_currentlyPlayingSample) && (_pMixer->isSoundHandleActive(_currentlyPlayingSample->hCurrentAud))) {
// Another sample is already playing, we have to stop that one
@@ -550,10 +568,18 @@ void SciMusic::soundStop(MusicEntry *pSnd) {
pSnd->status = kSoundStopped;
if (_soundVersion <= SCI_VERSION_0_LATE)
pSnd->isQueued = false;
- if (pSnd->pStreamAud) {
- if (_currentlyPlayingSample == pSnd)
- _currentlyPlayingSample = NULL;
- _pMixer->stopHandle(pSnd->hCurrentAud);
+ if (pSnd->isSample) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ g_sci->_audio32->stop(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
+ } else {
+#endif
+ if (_currentlyPlayingSample == pSnd)
+ _currentlyPlayingSample = NULL;
+ _pMixer->stopHandle(pSnd->hCurrentAud);
+#ifdef ENABLE_SCI32
+ }
+#endif
}
if (pSnd->pMidiParser) {
@@ -572,9 +598,12 @@ void SciMusic::soundStop(MusicEntry *pSnd) {
void SciMusic::soundSetVolume(MusicEntry *pSnd, byte volume) {
assert(volume <= MUSIC_VOLUME_MAX);
- if (pSnd->pStreamAud) {
- // we simply ignore volume changes for samples, because sierra sci also
- // doesn't support volume for samples via kDoSound
+ if (pSnd->isSample) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ g_sci->_audio32->setVolume(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj, volume);
+ }
+#endif
} else if (pSnd->pMidiParser) {
Common::StackLock lock(_mutex);
pSnd->pMidiParser->mainThreadBegin();
@@ -614,16 +643,25 @@ void SciMusic::soundKill(MusicEntry *pSnd) {
_mutex.unlock();
- if (pSnd->pStreamAud) {
- if (_currentlyPlayingSample == pSnd) {
- // Forget about this sound, in case it was currently playing
- _currentlyPlayingSample = NULL;
+ if (pSnd->isSample) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ g_sci->_audio32->stop(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
+ } else {
+#endif
+ if (_currentlyPlayingSample == pSnd) {
+ // Forget about this sound, in case it was currently playing
+ _currentlyPlayingSample = NULL;
+ }
+ _pMixer->stopHandle(pSnd->hCurrentAud);
+#ifdef ENABLE_SCI32
}
- _pMixer->stopHandle(pSnd->hCurrentAud);
+#endif
delete pSnd->pStreamAud;
pSnd->pStreamAud = NULL;
delete pSnd->pLoopStream;
pSnd->pLoopStream = 0;
+ pSnd->isSample = false;
}
_mutex.lock();
@@ -685,6 +723,18 @@ void SciMusic::soundResume(MusicEntry *pSnd) {
}
void SciMusic::soundToggle(MusicEntry *pSnd, bool pause) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && pSnd->isSample) {
+ if (pause) {
+ g_sci->_audio32->pause(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
+ } else {
+ g_sci->_audio32->resume(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
+ }
+
+ return;
+ }
+#endif
+
if (pause)
soundPause(pSnd);
else
@@ -813,6 +863,7 @@ MusicEntry::MusicEntry() {
pStreamAud = 0;
pLoopStream = 0;
pMidiParser = 0;
+ isSample = false;
for (int i = 0; i < 16; ++i) {
_usedChannels[i] = 0xFF;
diff --git a/engines/sci/sound/music.h b/engines/sci/sound/music.h
index a610f32d89..3a6de81c49 100644
--- a/engines/sci/sound/music.h
+++ b/engines/sci/sound/music.h
@@ -27,11 +27,18 @@
#include "common/mutex.h"
#include "audio/mixer.h"
-#include "audio/audiostream.h"
#include "sci/sci.h"
#include "sci/resource.h"
#include "sci/sound/drivers/mididriver.h"
+#ifdef ENABLE_SCI32
+#include "sci/sound/audio32.h"
+#endif
+
+namespace Audio {
+class LoopingAudioStream;
+class RewindableAudioStream;
+}
namespace Sci {
@@ -119,6 +126,7 @@ public:
Audio::RewindableAudioStream *pStreamAud;
Audio::LoopingAudioStream *pLoopStream;
Audio::SoundHandle hCurrentAud;
+ bool isSample;
public:
MusicEntry();
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index ee5903fda2..b9a764c93a 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -21,6 +21,9 @@
*/
#include "common/config-manager.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "sci/resource.h"
#include "sci/sound/audio.h"
#include "sci/sound/music.h"
#include "sci/sound/soundcmd.h"
@@ -44,7 +47,7 @@ SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segM
// resource number, but it's totally unrelated to the menu music).
// The GK1 demo (very late SCI1.1) does the same thing
// TODO: Check the QFG4 demo
- _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1 || ConfMan.getBool("prefer_digitalsfx"));
+ _useDigitalSFX = (getSciVersion() >= SCI_VERSION_2 || g_sci->getGameId() == GID_GK1DEMO || ConfMan.getBool("prefer_digitalsfx"));
_music = new SciMusic(_soundVersion, _useDigitalSFX);
_music->init();
@@ -95,12 +98,21 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) {
// user wants the digital version.
if (_useDigitalSFX || !newSound->soundRes) {
int sampleLen;
- newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen);
- newSound->soundType = Audio::Mixer::kSFXSoundType;
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ newSound->isSample = g_sci->getResMan()->testResource(ResourceId(kResourceTypeAudio, newSound->resourceId));
+ } else {
+#endif
+ newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen);
+ newSound->soundType = Audio::Mixer::kSFXSoundType;
+ newSound->isSample = newSound->pStreamAud != nullptr;
+#ifdef ENABLE_SCI32
+ }
+#endif
}
}
- if (!newSound->pStreamAud && newSound->soundRes)
+ if (!newSound->isSample && newSound->soundRes)
_music->soundInitSnd(newSound);
}
@@ -116,6 +128,7 @@ void SoundCommandParser::processInitSound(reg_t obj) {
newSound->resourceId = resourceId;
newSound->soundObj = obj;
newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
+ newSound->overridePriority = false;
if (_soundVersion <= SCI_VERSION_0_LATE)
newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
else
@@ -131,7 +144,7 @@ void SoundCommandParser::processInitSound(reg_t obj) {
_music->pushBackSlot(newSound);
- if (newSound->soundRes || newSound->pStreamAud) {
+ if (newSound->soundRes || newSound->isSample) {
// Notify the engine
if (_soundVersion <= SCI_VERSION_0_LATE)
writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
@@ -212,17 +225,6 @@ void SoundCommandParser::processPlaySound(reg_t obj, bool playBed) {
musicSlot->fadeStep = 0;
}
-reg_t SoundCommandParser::kDoSoundRestore(int argc, reg_t *argv, reg_t acc) {
- // Called after loading, to restore the playlist
- // We don't really use or need this
- return acc;
-}
-
-reg_t SoundCommandParser::kDoSoundDummy(int argc, reg_t *argv, reg_t acc) {
- warning("cmdDummy invoked"); // not supposed to occur
- return acc;
-}
-
reg_t SoundCommandParser::kDoSoundDispose(int argc, reg_t *argv, reg_t acc) {
debugC(kDebugLevelSound, "kDoSound(dispose): %04x:%04x", PRINT_REG(argv[0]));
processDisposeSound(argv[0]);
@@ -311,10 +313,22 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) {
}
reg_t obj = argv[0];
- uint16 value = argc > 1 ? argv[1].toUint16() : 0;
- if (!obj.getSegment()) { // pause the whole playlist
- _music->pauseAll(value);
- } else { // pause a playlist slot
+ const bool shouldPause = argc > 1 ? argv[1].toUint16() : false;
+ if (
+ (_soundVersion < SCI_VERSION_2_1_EARLY && !obj.getSegment()) ||
+ (_soundVersion >= SCI_VERSION_2_1_EARLY && obj.isNull())
+ ) {
+ _music->pauseAll(shouldPause);
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ if (shouldPause) {
+ g_sci->_audio32->pause(kAllChannels);
+ } else {
+ g_sci->_audio32->resume(kAllChannels);
+ }
+ }
+#endif
+ } else {
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
// This happens quite frequently
@@ -322,7 +336,23 @@ reg_t SoundCommandParser::kDoSoundPause(int argc, reg_t *argv, reg_t acc) {
return acc;
}
- _music->soundToggle(musicSlot, value);
+#ifdef ENABLE_SCI32
+ // NOTE: The original engine also expected a global
+ // "kernel call" flag to be true in order to perform
+ // this action, but the architecture of the ScummVM
+ // implementation is so different that it doesn't
+ // matter here
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) {
+ const int16 channelIndex = g_sci->_audio32->findChannelById(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj);
+
+ if (shouldPause) {
+ g_sci->_audio32->pause(channelIndex);
+ } else {
+ g_sci->_audio32->resume(channelIndex);
+ }
+ } else
+#endif
+ _music->soundToggle(musicSlot, shouldPause);
}
return acc;
}
@@ -352,7 +382,11 @@ reg_t SoundCommandParser::kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc)
int vol = CLIP<int16>(argv[0].toSint16(), 0, MUSIC_MASTERVOLUME_MAX);
vol = vol * Audio::Mixer::kMaxMixerVolume / MUSIC_MASTERVOLUME_MAX;
ConfMan.setInt("music_volume", vol);
- ConfMan.setInt("sfx_volume", vol);
+ // In SCI32, digital audio volume is controlled separately by
+ // kDoAudioVolume
+ if (_soundVersion < SCI_VERSION_2_1_EARLY) {
+ ConfMan.setInt("sfx_volume", vol);
+ }
g_engine->syncSoundSettings();
}
return acc;
@@ -375,6 +409,13 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {
int volume = musicSlot->volume;
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) {
+ g_sci->_audio32->fadeChannel(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj, argv[1].toSint16(), argv[2].toSint16(), argv[3].toSint16(), argc > 4 ? (bool)argv[4].toSint16() : false);
+ return acc;
+ }
+#endif
+
// If sound is not playing currently, set signal directly
if (musicSlot->status != kSoundPlaying) {
debugC(kDebugLevelSound, "kDoSound(fade): %04x:%04x fading requested, but sound is currently not playing", PRINT_REG(obj));
@@ -463,7 +504,18 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {
return;
}
- if (musicSlot->pStreamAud) {
+ if (musicSlot->isSample) {
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ const int position = g_sci->_audio32->getPosition(g_sci->_audio32->findChannelById(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj));
+
+ if (position == -1) {
+ processStopSound(musicSlot->soundObj, true);
+ }
+
+ return;
+ }
+#endif
// Update digital sound effect slots
uint currentLoopCounter = 0;
@@ -666,6 +718,12 @@ reg_t SoundCommandParser::kDoSoundSetVolume(int argc, reg_t *argv, reg_t acc) {
value = CLIP<int>(value, 0, MUSIC_VOLUME_MAX);
+#ifdef ENABLE_SCI32
+ // SSCI unconditionally sets volume if it is digital audio
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) {
+ _music->soundSetVolume(musicSlot, value);
+ }
+#endif
if (musicSlot->volume != value) {
musicSlot->volume = value;
_music->soundSetVolume(musicSlot, value);
@@ -724,6 +782,15 @@ reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) {
}
return acc;
}
+
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
+ if (value != -1) {
+ value = 1;
+ }
+ }
+#endif
+
if (value == -1) {
musicSlot->loop = 0xFFFF;
} else {
@@ -731,6 +798,13 @@ reg_t SoundCommandParser::kDoSoundSetLoop(int argc, reg_t *argv, reg_t acc) {
}
writeSelectorValue(_segMan, obj, SELECTOR(loop), musicSlot->loop);
+
+#ifdef ENABLE_SCI32
+ if (_soundVersion >= SCI_VERSION_2_1_EARLY && musicSlot->isSample) {
+ g_sci->_audio32->setLoop(ResourceId(kResourceTypeAudio, musicSlot->resourceId), musicSlot->soundObj, value == -1);
+ }
+#endif
+
return acc;
}
diff --git a/engines/sci/sound/sync.cpp b/engines/sci/sound/sync.cpp
new file mode 100644
index 0000000000..4e75dab725
--- /dev/null
+++ b/engines/sci/sound/sync.cpp
@@ -0,0 +1,76 @@
+/* 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.
+ *
+ */
+
+#include "sci/engine/kernel.h"
+#include "sci/util.h"
+#include "sync.h"
+
+namespace Sci {
+
+Sync::Sync(ResourceManager *resMan, SegManager *segMan) :
+ _resMan(resMan),
+ _segMan(segMan),
+ _resource(nullptr),
+ _offset(0) {}
+
+Sync::~Sync() {
+ stop();
+}
+
+void Sync::start(const ResourceId id, const reg_t syncObjAddr) {
+ _resource = _resMan->findResource(id, true);
+ _offset = 0;
+
+ if (_resource) {
+ writeSelectorValue(_segMan, syncObjAddr, SELECTOR(syncCue), 0);
+ } else {
+ warning("Sync::start: failed to find resource %s", id.toString().c_str());
+ // Notify the scripts to stop sound sync
+ writeSelectorValue(_segMan, syncObjAddr, SELECTOR(syncCue), SIGNAL_OFFSET);
+ }
+}
+
+void Sync::next(const reg_t syncObjAddr) {
+ if (_resource && (_offset < _resource->size - 1)) {
+ int16 syncCue = -1;
+ int16 syncTime = (int16)READ_SCI11ENDIAN_UINT16(_resource->data + _offset);
+
+ _offset += 2;
+
+ if ((syncTime != -1) && (_offset < _resource->size - 1)) {
+ syncCue = (int16)READ_SCI11ENDIAN_UINT16(_resource->data + _offset);
+ _offset += 2;
+ }
+
+ writeSelectorValue(_segMan, syncObjAddr, SELECTOR(syncTime), syncTime);
+ writeSelectorValue(_segMan, syncObjAddr, SELECTOR(syncCue), syncCue);
+ }
+}
+
+void Sync::stop() {
+ if (_resource) {
+ _resMan->unlockResource(_resource);
+ _resource = nullptr;
+ }
+}
+
+} // End of namespace Sci
diff --git a/engines/sci/sound/sync.h b/engines/sci/sound/sync.h
new file mode 100644
index 0000000000..4b9e2d1b3c
--- /dev/null
+++ b/engines/sci/sound/sync.h
@@ -0,0 +1,61 @@
+/* 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.
+ *
+ */
+
+#ifndef SCI_SOUND_SYNC_H
+#define SCI_SOUND_SYNC_H
+
+#include "sci/engine/selector.h"
+#include "sci/engine/vm_types.h"
+
+namespace Sci {
+
+enum AudioSyncCommands {
+ kSciAudioSyncStart = 0,
+ kSciAudioSyncNext = 1,
+ kSciAudioSyncStop = 2
+};
+
+class Resource;
+class ResourceManager;
+class SegManager;
+
+/**
+ * Sync class, kDoSync and relevant functions for SCI games.
+ * Provides AV synchronization for animations.
+ */
+class Sync {
+ SegManager *_segMan;
+ ResourceManager *_resMan;
+ Resource *_resource;
+ uint _offset;
+
+public:
+ Sync(ResourceManager *resMan, SegManager *segMan);
+ ~Sync();
+
+ void start(const ResourceId id, const reg_t syncObjAddr);
+ void next(const reg_t syncObjAddr);
+ void stop();
+};
+
+} // End of namespace Sci
+#endif
diff --git a/engines/scumm/POTFILES b/engines/scumm/POTFILES
index 246f14d3f0..039aa16755 100644
--- a/engines/scumm/POTFILES
+++ b/engines/scumm/POTFILES
@@ -1,3 +1,4 @@
+engines/scumm/detection.cpp
engines/scumm/dialogs.cpp
engines/scumm/help.cpp
engines/scumm/input.cpp
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 3a69b5f03c..b3e7926015 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -259,6 +259,8 @@ void Actor_v0::initActor(int mode) {
_limb_flipped[i] = false;
}
+ walkBoxQueueReset();
+
if (_vm->_game.features & GF_DEMO) {
_sound[0] = v0ActorDemoTalk[_number];
} else {
@@ -266,6 +268,116 @@ void Actor_v0::initActor(int mode) {
}
}
+void Actor_v0::walkBoxQueueReset() {
+ _walkboxHistory.clear();
+ _walkboxQueueIndex = 0;
+
+ for (uint i = 0; i < ARRAYSIZE(_walkboxQueue); ++i) {
+ _walkboxQueue[i] = kInvalidBox;
+ }
+}
+
+bool Actor_v0::walkBoxQueueAdd(int box) {
+
+ if (_walkboxQueueIndex == ARRAYSIZE(_walkboxQueue))
+ return false;
+
+ _walkboxQueue[_walkboxQueueIndex++] = box;
+ _walkboxHistory.push_back(box);
+ return true;
+}
+
+void Actor_v0::walkboxQueueReverse() {
+ int j = ARRAYSIZE(_walkboxQueue) - 1;
+
+ while (_walkboxQueue[j] == kInvalidBox && j >= 1)
+ --j;
+
+ if (j <= 1)
+ return;
+
+ for (int i = 1; i < j && j >= 1 ; ++i, --j) {
+
+ byte tmp = _walkboxQueue[i];
+
+ _walkboxQueue[i] = _walkboxQueue[j];
+ _walkboxQueue[j] = tmp;
+ }
+}
+
+bool Actor_v0::walkBoxQueueFind(int box) {
+
+ for (uint i = 0; i < _walkboxHistory.size(); ++i) {
+ if (box == _walkboxHistory[i])
+ return true;
+ }
+
+ return false;
+}
+
+bool Actor_v0::walkBoxQueuePrepare() {
+ walkBoxQueueReset();
+ int BoxFound = _walkbox;
+
+ if (BoxFound == _walkdata.destbox) {
+
+ _newWalkBoxEntered = true;
+ return true;
+ }
+
+ // Build a series of walkboxes from our current position, to the target
+ do {
+ // Add the current box to the queue
+ if (!walkBoxQueueAdd(BoxFound))
+ return false;
+
+ // Loop until we find a walkbox which hasn't been tested
+ while (_walkboxQueueIndex > 0) {
+
+ // Check if the dest box is a direct neighbour
+ if ((BoxFound = _vm->getNextBox(BoxFound, _walkdata.destbox)) == kInvalidBox) {
+
+ // Its not, start hunting through this boxes immediate connections
+ byte* boxm = _vm->getBoxConnectionBase(_walkboxQueue[_walkboxQueueIndex - 1]);
+
+ // Attempt to find one, which we havn't already used
+ for (; *boxm != kInvalidBox; ++boxm) {
+ if (walkBoxQueueFind(*boxm) != true)
+ break;
+ }
+
+ BoxFound = *boxm;
+ }
+
+ // Found one?
+ if (BoxFound != kInvalidBox) {
+
+ // Did we find a connection to the final walkbox
+ if (BoxFound == _walkdata.destbox) {
+
+ _newWalkBoxEntered = true;
+
+ walkBoxQueueAdd(BoxFound);
+
+ walkboxQueueReverse();
+ return true;
+ }
+
+ // Nope, check the next box
+ break;
+ }
+
+ // Drop this box, its useless to us
+ _walkboxQueue[--_walkboxQueueIndex] = kInvalidBox;
+
+ BoxFound = _walkboxQueue[_walkboxQueueIndex - 1];
+ }
+
+ } while (_walkboxQueueIndex > 0);
+
+ return false;
+}
+
void Actor::setBox(int box) {
_walkbox = box;
setupActorScale();
@@ -634,17 +746,18 @@ void Actor::startWalkActor(int destX, int destY, int dir) {
_walkdata.dest.y = abr.y;
_walkdata.destbox = abr.box;
_walkdata.destdir = dir;
-
+ _walkdata.point3.x = 32000;
+ _walkdata.curbox = _walkbox;
+
if (_vm->_game.version == 0) {
- ((Actor_v0*)this)->_newWalkBoxEntered = true;
+ ((Actor_v0 *)this)->walkBoxQueuePrepare();
+
} else if (_vm->_game.version <= 2) {
_moving = (_moving & ~(MF_LAST_LEG | MF_IN_LEG)) | MF_NEW_LEG;
} else {
_moving = (_moving & MF_IN_LEG) | MF_NEW_LEG;
}
- _walkdata.point3.x = 32000;
- _walkdata.curbox = _walkbox;
}
void Actor::startWalkAnim(int cmd, int angle) {
@@ -861,13 +974,7 @@ L2C36:;
stopActorMoving();
return;
}
- // 2C98: Yes, an exact copy of what just occurred.. the original does this, so im doing it...
- // Just to keep me sane when going over it :)
- if (A == 0xFF) {
- setActorFromTmp();
- stopActorMoving();
- return;
- }
+
return;
}
@@ -1398,13 +1505,13 @@ void Actor::putActor(int dstX, int dstY, int newRoom) {
showActor();
}
- // V0 always sets the actor to face the camera upon entering a room
if (_vm->_game.version == 0) {
- _walkdata.dest = _pos;
- ((Actor_v0*)this)->_newWalkBoxEntered = true;
- ((Actor_v0*)this)->_CurrentWalkTo = _pos;
+ ((Actor_v0 *)this)->_newWalkBoxEntered = false;
+ ((Actor_v0 *)this)->_CurrentWalkTo = _pos;
+ ((Actor_v0 *)this)->_NewWalkTo = _pos;
+ // V0 always sets the actor to face the camera upon entering a room
setDirection(oldDirToNewDir(2));
}
}
@@ -1549,7 +1656,7 @@ AdjustBoxResult Actor_v0::adjustPosInBorderWalkbox(AdjustBoxResult box) {
if (A < box.x)
return box;
- if (A < 0xA0 || A == 0xA0)
+ if (A <= 0xA0)
A = 0;
Result.x = A;
@@ -1980,9 +2087,10 @@ void ScummEngine::processActors() {
if (_game.version == 0) {
// 0x057B
Actor_v0 *a0 = (Actor_v0*) a;
- if (a0->_speaking & 1)
+ if (a0->_speaking & 1) {
a0->_speaking ^= 0xFE;
-
+ ++_V0Delay._actorRedrawCount;
+ }
// 0x22B5
if (a0->_miscflags & kActorMiscFlagHide)
continue;
@@ -2404,8 +2512,13 @@ void Actor_v0::limbFrameCheck(int limb) {
void Actor_v0::animateCostume() {
speakCheck();
- if (_vm->_costumeLoader->increaseAnims(this))
+ byte count = _vm->_costumeLoader->increaseAnims(this);
+
+ if (count) {
+ _vm->_V0Delay._actorLimbRedrawDrawCount += count;
+
_needRedraw = true;
+ }
}
void Actor_v0::speakCheck() {
@@ -2479,6 +2592,13 @@ void ScummEngine::setActorRedrawFlags() {
_actors[j]->_needRedraw = true;
}
} else {
+ if (_game.heversion >= 72) {
+ for (j = 1; j < _numActors; j++) {
+ if (_actors[j]->_costume && _actors[j]->_heXmapNum)
+ _actors[j]->_needRedraw = true;
+ }
+ }
+
for (i = 0; i < _gdi->_numStrips; i++) {
int strip = _screenStartStrip + i;
if (testGfxAnyUsageBits(strip)) {
@@ -3247,7 +3367,7 @@ void Actor_v0::animateActor(int anim) {
} else {
- if (anim > 4 && anim <= 7)
+ if (anim >= 4 && anim <= 7)
_facing = normalizeAngle(oldDirToNewDir(dir));
}
}
@@ -3304,13 +3424,13 @@ void Actor_v0::setActorFromTmp() {
}
void Actor_v0::actorSetWalkTo() {
-
+
if (_newWalkBoxEntered == false)
return;
_newWalkBoxEntered = false;
- int nextBox = ((ScummEngine_v0*)_vm)->walkboxFindTarget(this, _walkdata.destbox, _walkdata.dest);
+ int nextBox = ((ScummEngine_v0 *)_vm)->walkboxFindTarget(this, _walkdata.destbox, _walkdata.dest);
if (nextBox != kInvalidBox) {
_walkdata.curbox = nextBox;
}
@@ -3343,10 +3463,38 @@ void Actor_v0::saveLoadWithSerializer(Serializer *ser) {
MKLINE(Actor_v0, _walkYCount, sleByte, VER(97)),
MKLINE(Actor_v0, _walkYCountInc, sleByte, VER(97)),
MKLINE(Actor_v0, _walkMaxXYCountInc, sleByte, VER(97)),
+
+ MKARRAY(Actor_v0, _walkboxQueue[0], sleByte, 16, VER(98)),
+ MKLINE(Actor_v0, _walkboxQueueIndex, sleByte, VER(98)),
MKEND()
};
ser->saveLoadEntries(this, actorEntries);
+
+ // When loading, we need to ensure the limbs are restarted
+ if (ser->isLoading()) {
+
+ // valid costume command?
+ if (_costCommand != 0xFF) {
+
+ // Do we have a walkbox queue?
+ if (_walkboxQueueIndex < 1) {
+ _costCommand = 0xFF;
+
+ // Standing Still
+ setDirection(_facing);
+ speakCheck();
+
+ } else {
+ // Force limb direction update
+ _facing = 0;
+ directionUpdate();
+
+ // Begin walking
+ animateActor(newDirToOldDir(_facing));
+ }
+ }
+ }
}
void Actor::saveLoadWithSerializer(Serializer *ser) {
@@ -3489,6 +3637,8 @@ void Actor::saveLoadWithSerializer(Serializer *ser) {
_walkdata.point3.x >>= V12_X_SHIFT;
_walkdata.point3.y >>= V12_Y_SHIFT;
}
+
+ setDirection(_facing);
}
}
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index c1a3f23318..62ba161f4e 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -350,6 +350,11 @@ class Actor_v0 : public Actor_v2 {
public:
Common::Point _CurrentWalkTo, _NewWalkTo;
+ Common::Array<byte> _walkboxHistory;
+
+ byte _walkboxQueue[0x10];
+ byte _walkboxQueueIndex;
+
byte _costCommandNew;
byte _costCommand;
byte _miscflags;
@@ -380,6 +385,12 @@ public:
bool _limb_flipped[8];
+private:
+
+ bool walkBoxQueueAdd(int box);
+ bool walkBoxQueueFind(int box);
+ void walkboxQueueReverse();
+
public:
Actor_v0(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {}
@@ -401,6 +412,9 @@ public:
byte actorWalkY();
byte updateWalkbox();
+ void walkBoxQueueReset();
+ bool walkBoxQueuePrepare();
+
AdjustBoxResult adjustXYToBeInBox(int dstX, int dstY);
AdjustBoxResult adjustPosInBorderWalkbox(AdjustBoxResult box);
diff --git a/engines/scumm/boxes.cpp b/engines/scumm/boxes.cpp
index 087d8425ac..b5caec3c4f 100644
--- a/engines/scumm/boxes.cpp
+++ b/engines/scumm/boxes.cpp
@@ -692,6 +692,22 @@ byte *ScummEngine::getBoxMatrixBaseAddr() {
return ptr;
}
+byte *ScummEngine::getBoxConnectionBase(int box) {
+ byte *boxm = getBoxMatrixBaseAddr();
+
+ int boxIndex = 0;
+
+ for (; boxIndex != box; ++boxIndex) {
+
+ while (*boxm != 0xFF) {
+ ++boxm;
+ }
+
+ ++boxm;
+ }
+
+ return boxm;
+}
/**
* Compute if there is a way that connects box 'from' with box 'to'.
* Returns the number of a box adjacent to 'from' that is the next on the
@@ -719,21 +735,18 @@ int ScummEngine::getNextBox(byte from, byte to) {
boxm = getBoxMatrixBaseAddr();
if (_game.version == 0) {
- // calculate shortest paths
- byte *itineraryMatrix = (byte *)malloc(numOfBoxes * numOfBoxes);
- calcItineraryMatrix(itineraryMatrix, numOfBoxes);
- dest = to;
- do {
- dest = itineraryMatrix[numOfBoxes * from + dest];
- } while (dest != Actor::kInvalidBox && !areBoxesNeighbors(from, dest));
+ boxm = getBoxConnectionBase(from);
- if (dest == Actor::kInvalidBox)
- dest = -1;
+ for (; *boxm != 0xFF; ++boxm) {
+ if (*boxm == to)
+ break;
+ }
- free(itineraryMatrix);
- return dest;
- } else if (_game.version <= 2) {
+ return *boxm;
+
+ }
+ else if (_game.version <= 2) {
// The v2 box matrix is a real matrix with numOfBoxes rows and columns.
// The first numOfBoxes bytes contain indices to the start of the corresponding
// row (although that seems unnecessary to me - the value is easily computable.
@@ -967,6 +980,7 @@ void ScummEngine::calcItineraryMatrix(byte *itineraryMatrix, int num) {
// 255 (= infinity) to all other boxes.
for (i = 0; i < num; i++) {
for (j = 0; j < num; j++) {
+
if (i == j) {
adjacentMatrix[i * boxSize + j] = 0;
itineraryMatrix[i * boxSize + j] = j;
@@ -1159,21 +1173,32 @@ bool ScummEngine::areBoxesNeighbors(int box1nr, int box2nr) {
}
byte ScummEngine_v0::walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest) {
- Actor_v0 *Actor = (Actor_v0*)a;
+ Actor_v0 *Actor = (Actor_v0 *)a;
+ byte nextBox = kOldInvalidBox;
- byte nextBox = getNextBox(a->_walkbox, destbox);
+ // Do we have a walkbox queue to process
+ if (Actor->_walkboxQueueIndex > 1) {
+ nextBox = Actor->_walkboxQueue[--Actor->_walkboxQueueIndex];
- if (nextBox != 0xFF && nextBox == destbox && areBoxesNeighbors(a->_walkbox, nextBox)) {
+ if (Actor->_walkboxQueueIndex <= 1) {
+ Actor->walkBoxQueueReset();
+ }
+ }
+
+ // Target box reached?
+ if (nextBox != Actor::kInvalidBox && nextBox == destbox && areBoxesNeighbors(a->_walkbox, nextBox)) {
Actor->_NewWalkTo = walkdest;
return nextBox;
}
- if (nextBox != 0xFF && nextBox != a->_walkbox) {
+ // Next box reached
+ if (nextBox != Actor::kInvalidBox && nextBox != a->_walkbox) {
- getClosestPtOnBox(getBoxCoordinates(nextBox), a->getPos().x, a->getPos().y, Actor->_NewWalkTo.x, Actor->_NewWalkTo.y);
+ getClosestPtOnBox(getBoxCoordinates(nextBox), a->getRealPos().x, a->getRealPos().y, Actor->_NewWalkTo.x, Actor->_NewWalkTo.y);
} else {
+
if (walkdest.x == -1)
Actor->_NewWalkTo = Actor->_CurrentWalkTo;
else
diff --git a/engines/scumm/charset-fontdata.cpp b/engines/scumm/charset-fontdata.cpp
index 23e89b1878..a1e92a9950 100644
--- a/engines/scumm/charset-fontdata.cpp
+++ b/engines/scumm/charset-fontdata.cpp
@@ -591,35 +591,40 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language)
_fontHeight = 8;
_curId = 0;
- const byte *replacementData = NULL;
+ const byte *replacementMap = NULL, *replacementData = NULL;
int replacementChars = 0;
switch (language) {
case Common::DE_DEU:
if (_vm->_game.version == 0) {
- replacementData = germanCharsetDataV0;
+ replacementMap = germanCharsetDataV0;
replacementChars = sizeof(germanCharsetDataV0) / 2;
} else {
- replacementData = germanCharsetDataV2;
+ replacementMap = germanCharsetDataV2;
replacementChars = sizeof(germanCharsetDataV2) / 2;
}
+ replacementData = specialCharsetData;
break;
case Common::FR_FRA:
- replacementData = frenchCharsetDataV2;
+ replacementMap = frenchCharsetDataV2;
replacementChars = sizeof(frenchCharsetDataV2) / 2;
+ replacementData = specialCharsetData;
break;
case Common::IT_ITA:
- replacementData = italianCharsetDataV2;
+ replacementMap = italianCharsetDataV2;
replacementChars = sizeof(italianCharsetDataV2) / 2;
+ replacementData = specialCharsetData;
break;
case Common::ES_ESP:
- replacementData = spanishCharsetDataV2;
+ replacementMap = spanishCharsetDataV2;
replacementChars = sizeof(spanishCharsetDataV2) / 2;
+ replacementData = specialCharsetData;
break;
case Common::RU_RUS:
if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) {
- replacementData = russCharsetDataV2;
+ replacementMap = russCharsetDataV2;
replacementChars = sizeof(russCharsetDataV2) / 2;
+ replacementData = russianCharsetDataV2;
} else {
_fontPtr = russianCharsetDataV2;
}
@@ -629,20 +634,16 @@ CharsetRendererV2::CharsetRendererV2(ScummEngine *vm, Common::Language language)
break;
}
- if (replacementData) {
+ if (replacementMap && replacementData) {
_fontPtr = new byte[sizeof(englishCharsetDataV2)];
_deleteFontPtr = true;
memcpy(const_cast<byte *>(_fontPtr), englishCharsetDataV2, sizeof(englishCharsetDataV2));
for (int i = 0; i < replacementChars; i++) {
- int ch1 = replacementData[2 * i];
- int ch2 = replacementData[2 * i + 1];
+ int ch1 = replacementMap[2 * i];
+ int ch2 = replacementMap[2 * i + 1];
- if (((_vm->_game.id == GID_MANIAC) || (_vm->_game.id == GID_ZAK)) && (_vm->_game.version == 2)) {
- memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, russianCharsetDataV2 + 8 * ch2, 8);
- } else {
- memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, specialCharsetData + 8 * ch2, 8);
- }
+ memcpy(const_cast<byte *>(_fontPtr) + 8 * ch1, replacementData + 8 * ch2, 8);
}
} else
_deleteFontPtr = false;
diff --git a/engines/scumm/configure.engine b/engines/scumm/configure.engine
index e1de788061..e8962a371e 100644
--- a/engines/scumm/configure.engine
+++ b/engines/scumm/configure.engine
@@ -2,4 +2,4 @@
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine scumm "SCUMM" yes "scumm_7_8 he" "v0-v6 games"
add_engine scumm_7_8 "v7 & v8 games" yes
-add_engine he "HE71+ games" yes
+add_engine he "HE71+ games" yes "" "" "highres"
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index 0ebea94608..617c2ab85f 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -411,14 +411,15 @@ bool ScummDebugger::Cmd_PrintActor(int argc, const char **argv) {
int i;
Actor *a;
- debugPrintf("+---------------------------------------------------------------+\n");
- debugPrintf("|# | x | y | w | h |elev|cos|box|mov| zp|frm|scl|dir| cls |\n");
- debugPrintf("+--+----+----+---+---+----+---+---+---+---+---+---+---+---------+\n");
+ debugPrintf("+----------------------------------------------------------------------------+\n");
+ debugPrintf("|# | name | x | y | w | h |elev|cos|box|mov| zp|frm|scl|dir| cls |\n");
+ debugPrintf("+--+------------+----+----+---+---+----+---+---+---+---+---+---+---+---------+\n");
for (i = 1; i < _vm->_numActors; i++) {
a = _vm->_actors[i];
+ const byte *name = _vm->getObjOrActorName(_vm->actorToObj(a->_number));
if (a->_visible)
- debugPrintf("|%2d|%4d|%4d|%3d|%3d|%4d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|$%08x|\n",
- a->_number, a->getRealPos().x, a->getRealPos().y, a->_width, a->_bottom - a->_top,
+ debugPrintf("|%2d|%-12.12s|%4d|%4d|%3d|%3d|%4d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|$%08x|\n",
+ a->_number, name, a->getRealPos().x, a->getRealPos().y, a->_width, a->_bottom - a->_top,
a->getElevation(),
a->_costume, a->_walkbox, a->_moving, a->_forceClip, a->_frame,
a->_scalex, a->getFacing(), _vm->_classData[a->_number]);
@@ -431,17 +432,18 @@ bool ScummDebugger::Cmd_PrintObjects(int argc, const char **argv) {
int i;
ObjectData *o;
debugPrintf("Objects in current room\n");
- debugPrintf("+---------------------------------+------------+\n");
- debugPrintf("|num | x | y |width|height|state|fl| cls |\n");
- debugPrintf("+----+----+----+-----+------+-----+--+---------+\n");
+ debugPrintf("+-----------------------------------------------------------+\n");
+ debugPrintf("|num | name | x | y |width|height|state|fl| cls |\n");
+ debugPrintf("+----+------------+----+----+-----+------+-----+--+---------+\n");
for (i = 1; i < _vm->_numLocalObjects; i++) {
o = &(_vm->_objs[i]);
if (o->obj_nr == 0)
continue;
int classData = (_vm->_game.version != 0 ? _vm->_classData[o->obj_nr] : 0);
- debugPrintf("|%4d|%4d|%4d|%5d|%6d|%5d|%2d|$%08x|\n",
- o->obj_nr, o->x_pos, o->y_pos, o->width, o->height, o->state,
+ const byte *name = _vm->getObjOrActorName(o->obj_nr);
+ debugPrintf("|%4d|%-12.12s|%4d|%4d|%5d|%6d|%5d|%2d|$%08x|\n",
+ o->obj_nr, name, o->x_pos, o->y_pos, o->width, o->height, o->state,
o->fl_object_index, classData);
}
debugPrintf("\n");
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index 9264a6443b..4c9d1221aa 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -29,6 +29,7 @@
#include "common/md5.h"
#include "common/savefile.h"
#include "common/system.h"
+#include "common/translation.h"
#include "audio/mididrv.h"
@@ -185,6 +186,11 @@ Common::String ScummEngine_v70he::generateFilename(const int room) const {
}
if (_filenamePattern.genMethod == kGenHEPC || _filenamePattern.genMethod == kGenHEIOS) {
+ if (id == '3' && _game.id == GID_MOONBASE) {
+ result = Common::String::format("%s.u32", _filenamePattern.pattern);
+ break;
+ }
+
// For HE >= 98, we already called snprintf above.
if (_game.heversion < 98 || room < 0)
result = Common::String::format("%s.he%c", _filenamePattern.pattern, id);
@@ -957,6 +963,7 @@ public:
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
};
bool ScummMetaEngine::hasFeature(MetaEngineFeature f) const {
@@ -1329,6 +1336,21 @@ SaveStateDescriptor ScummMetaEngine::querySaveMetaInfos(const char *target, int
return desc;
}
+static const ExtraGuiOption comiObjectLabelsOption = {
+ _s("Show Object Line"),
+ _s("Show the names of objects at the bottom of the screen"),
+ "object_labels",
+ true
+};
+
+const ExtraGuiOptions ScummMetaEngine::getExtraGuiOptions(const Common::String &target) const {
+ ExtraGuiOptions options;
+ if (target.empty() || ConfMan.get("gameid", target) == "comi") {
+ options.push_back(comiObjectLabelsOption);
+ }
+ return options;
+}
+
#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 5a994cb699..bb3e7f6ec3 100644
--- a/engines/scumm/detection_tables.h
+++ b/engines/scumm/detection_tables.h
@@ -245,9 +245,11 @@ static const GameSettings gameVariantsTable[] = {
{"monkey", "CD", 0, GID_MONKEY, 5, 0, MDT_ADLIB, GF_AUDIOTRACKS, UNK, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
{"monkey", "FM-TOWNS", 0, GID_MONKEY, 5, 0, MDT_TOWNS, GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GUIO_MIDITOWNS, GUIO_NOASPECT)},
{"monkey", "SEGA", 0, GID_MONKEY, 5, 0, MDT_NONE, GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI)},
+ {"monkey", "SE Talkie", 0, GID_MONKEY, 5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, GF_AUDIOTRACKS, UNK, GUIO0()},
{"monkey2", "", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO1(GUIO_NOSPEECH)},
{"monkey2", "FM-TOWNS", 0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_TOWNS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, Common::kPlatformFMTowns, GUIO5(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_NOASPECT)},
+ {"monkey2", "SE Talkie",0, GID_MONKEY2, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
{"atlantis", "", 0, GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
{"atlantis", "Steam", "steam", GID_INDY4, 5, 0, MDT_PCSPK | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO0()},
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 21c7428621..9b09f426ef 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -33,10 +33,8 @@
#include "scummhelp.h"
#endif
-#include "gui/about.h"
-
#include "gui/gui-manager.h"
-#include "gui/widgets/list.h"
+#include "gui/widget.h"
#include "gui/ThemeEval.h"
#include "scumm/dialogs.h"
@@ -45,14 +43,12 @@
#include "scumm/imuse/imuse.h"
#include "scumm/imuse_digi/dimuse.h"
#include "scumm/verbs.h"
-#include "audio/mididrv.h"
-#include "audio/mixer.h"
#ifndef DISABLE_HELP
#include "scumm/help.h"
#endif
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
#include "gui/KeysDialog.h"
#endif
@@ -153,8 +149,8 @@ static const ResString string_map_table_v6[] = {
{91, "Unable to Find %s, (%c%d) Press Button."},
{92, "Error reading disk %c, (%c%d) Press Button."},
{93, "Game Paused. Press SPACE to Continue."},
- {94, "Are you sure you want to restart? (Y/N)"},
- {95, "Are you sure you want to quit? (Y/N)"},
+ {94, "Are you sure you want to restart? (Y/N)Y"},
+ {95, "Are you sure you want to quit? (Y/N)Y"},
{96, "Save"},
{97, "Load"},
{98, "Play"},
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 08222dd8cd..bd0645597e 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -24,15 +24,13 @@
#define SCUMM_DIALOGS_H
#include "common/str.h"
+#include "common/keyboard.h"
#include "gui/dialog.h"
-#include "gui/widget.h"
#include "engines/dialogs.h"
-#include "scumm/detection.h"
-
namespace GUI {
-class ListWidget;
class CommandSender;
+class StaticTextWidget;
}
diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp
index 1d1b6b4f13..48818b8abf 100644
--- a/engines/scumm/gfx.cpp
+++ b/engines/scumm/gfx.cpp
@@ -3795,6 +3795,11 @@ void ScummEngine::fadeOut(int effect) {
_textSurface.fillRect(Common::Rect(0, vs->topline * _textSurfaceMultiplier, _textSurface.pitch, (vs->topline + vs->h) * _textSurfaceMultiplier), 0);
#endif
+ // V0 wipes the text area before fading out
+ if (_game.version == 0) {
+ updateDirtyScreen(kTextVirtScreen);
+ }
+
// TheDig can disable fadeIn(), and may call fadeOut() several times
// successively. Disabling the _screenEffectFlag check forces the screen
// to get cleared. This fixes glitches, at least, in the first cutscenes
diff --git a/engines/scumm/gfx.h b/engines/scumm/gfx.h
index 42844daf30..86913f9e2e 100644
--- a/engines/scumm/gfx.h
+++ b/engines/scumm/gfx.h
@@ -58,7 +58,7 @@ struct CameraData {
/** Virtual screen identifiers */
enum VirtScreenNumber {
kMainVirtScreen = 0, // The 'stage'
- kTextVirtScreen = 1, // In V1-V3 games: the area where text is printed
+ kTextVirtScreen = 1, // In V0-V3 games: the area where text is printed
kVerbVirtScreen = 2, // The verb area
kUnkVirtScreen = 3 // ?? Not sure what this one is good for...
};
diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp
index 8483a8a402..0a3a56ceda 100644
--- a/engines/scumm/he/animation_he.cpp
+++ b/engines/scumm/he/animation_he.cpp
@@ -22,16 +22,21 @@
#ifdef ENABLE_HE
+#include "common/scummsys.h"
+
#include "scumm/he/animation_he.h"
#include "scumm/he/intern_he.h"
-#include "audio/audiostream.h"
#include "video/smk_decoder.h"
#ifdef USE_BINK
#include "video/bink_decoder.h"
#endif
+namespace Audio {
+class Mixer;
+}
+
namespace Scumm {
MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) {
diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h
index 677a4b4247..6891ed8bf0 100644
--- a/engines/scumm/he/animation_he.h
+++ b/engines/scumm/he/animation_he.h
@@ -23,7 +23,9 @@
#if !defined(SCUMM_HE_ANIMATION_H) && defined(ENABLE_HE)
#define SCUMM_HE_ANIMATION_H
-#include "audio/mixer.h"
+namespace Audio {
+class Mixer;
+}
namespace Common {
class String;
diff --git a/engines/scumm/he/cup_player_he.cpp b/engines/scumm/he/cup_player_he.cpp
index c409863804..3a7ad49c2f 100644
--- a/engines/scumm/he/cup_player_he.cpp
+++ b/engines/scumm/he/cup_player_he.cpp
@@ -408,6 +408,9 @@ void CUP_Player::handleSRLE(Common::SeekableReadStream &dataStream, uint32 dataS
static void decodeLZSS(uint8 *dst, const uint8 *src1, const uint8 *src2, const uint8 *src3) {
uint8 wnd[4096];
int index = 1;
+
+ memset(wnd, 0, sizeof(wnd));
+
while (1) {
int code = *src1++;
for (int b = 0; b < 8; ++b) {
diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 370f54c1d8..c6abac3ecc 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -121,13 +121,24 @@ class ScummEngine_v70he : public ScummEngine_v60he {
friend class ResExtractor;
protected:
+ enum HESndFlags {
+ HE_SND_LOOP = 1,
+ HE_SND_APPEND = 2,
+ HE_SND_SOFT_SOUND = 4,
+ HE_SND_QUICK_START = 8,
+ HE_SND_OFFSET = 16,
+ HE_SND_VOL = 32,
+ HE_SND_FREQUENCY = 64,
+ HE_SND_PAN = 128
+ };
+
ResExtractor *_resExtractor;
byte *_heV7DiskOffsets;
byte *_heV7RoomOffsets;
uint32 *_heV7RoomIntOffsets;
- int32 _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags, _heSndSoundFreq;
+ int32 _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags, _heSndSoundFreq, _heSndPan, _heSndVol;
int _numStoredFlObjects;
ObjectData *_storedFlObjects;
@@ -168,7 +179,7 @@ protected:
virtual void setDefaultCursor();
/* HE version 70 script opcodes */
- void o70_startSound();
+ void o70_soundOps();
void o70_pickupObject();
void o70_getActorRoom();
void o70_resourceRoutines();
@@ -184,8 +195,11 @@ protected:
};
#ifdef ENABLE_HE
+class Moonbase;
+
class ScummEngine_v71he : public ScummEngine_v70he {
friend class Wiz;
+ friend class Moonbase;
protected:
bool _skipProcessActors;
@@ -423,6 +437,7 @@ protected:
class ScummEngine_v90he : public ScummEngine_v80he {
friend class LogicHE;
+ friend class Moonbase;
friend class MoviePlayer;
friend class Sprite;
@@ -433,7 +448,7 @@ protected:
byte filename[260];
int32 status;
int32 flags;
- int32 unk2;
+ int32 number;
int32 wizResNum;
};
@@ -571,16 +586,25 @@ protected:
};
class ScummEngine_v100he : public ScummEngine_v99he {
+friend class AI;
+
protected:
ResType _heResType;
int32 _heResId;
byte _debugInputBuffer[256];
+
public:
- ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {}
+ Moonbase *_moonbase;
+
+public:
+ ScummEngine_v100he(OSystem *syst, const DetectorResult &dr);
+ ~ScummEngine_v100he();
virtual void resetScumm();
+ virtual void setupScummVars();
+
protected:
virtual void setupOpcodes();
@@ -609,7 +633,7 @@ protected:
void o100_redimArray();
void o100_roomOps();
void o100_setSystemMessage();
- void o100_startSound();
+ void o100_soundOps();
void o100_setSpriteInfo();
void o100_startScript();
void o100_systemOps();
@@ -626,6 +650,14 @@ protected:
void o100_getSpriteInfo();
void o100_getWizData();
void o100_getVideoData();
+
+protected:
+ byte VAR_U32_USER_VAR_A;
+ byte VAR_U32_USER_VAR_B;
+ byte VAR_U32_USER_VAR_C;
+ byte VAR_U32_USER_VAR_D;
+ byte VAR_U32_USER_VAR_E;
+ byte VAR_U32_USER_VAR_F;
};
class ScummEngine_vCUPhe : public Engine {
diff --git a/engines/scumm/he/logic/moonbase_logic.cpp b/engines/scumm/he/logic/moonbase_logic.cpp
new file mode 100644
index 0000000000..1b596fc54c
--- /dev/null
+++ b/engines/scumm/he/logic/moonbase_logic.cpp
@@ -0,0 +1,255 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/logic_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+/**
+ * Logic code for:
+ * Moonbase Commander
+ */
+class LogicHEmoonbase : public LogicHE {
+public:
+ LogicHEmoonbase(ScummEngine_v100he *vm) : LogicHE(vm) { _vm1 = vm; }
+
+ int versionID();
+
+ int32 dispatch(int op, int numArgs, int32 *args);
+
+private:
+ void op_create_multi_state_wiz(int op, int numArgs, int32 *args);
+ void op_load_multi_channel_wiz(int op, int numArgs, int32 *args);
+ void op_wiz_from_multi_channel_wiz(int op, int numArgs, int32 *args);
+ void op_dos_command(int op, int numArgs, int32 *args);
+ void op_set_fow_sentinel(int32 *args);
+ void op_set_fow_information(int op, int numArgs, int32 *args);
+ int op_set_fow_image(int op, int numArgs, int32 *args);
+
+ void op_ai_test_kludge(int op, int numArgs, int32 *args);
+ int op_ai_master_control_program(int op, int numArgs, int32 *args);
+ void op_ai_reset(int op, int numArgs, int32 *args);
+ void op_ai_set_type(int op, int numArgs, int32 *args);
+ void op_ai_clean_up(int op, int numArgs, int32 *args);
+
+private:
+ ScummEngine_v100he *_vm1;
+};
+
+int LogicHEmoonbase::versionID() {
+ if (_vm->_game.features & GF_DEMO)
+ return -100;
+ else if (strcmp(_vm->_game.variant, "1.1") == 0)
+ return 110;
+ else
+ return 100;
+}
+
+#define OP_CREATE_MULTI_STATE_WIZ 100
+#define OP_LOAD_MULTI_CHANNEL_WIZ 101
+#define OP_WIZ_FROM_MULTI_CHANNEL_WIZ 102
+#define OP_DOS_COMMAND 103
+#define OP_SET_FOW_SENTINEL 104
+#define OP_SET_FOW_INFORMATION 105
+#define OP_SET_FOW_IMAGE 106
+
+#define OP_AI_TEST_KLUDGE 10000
+#define OP_AI_MASTER_CONTROL_PROGRAM 10001
+#define OP_AI_RESET 10002
+#define OP_AI_SET_TYPE 10003
+#define OP_AI_CLEAN_UP 10004
+
+#define OP_NET_REMOTE_START_SCRIPT 1492
+#define OP_NET_DO_INIT_ALL 1493
+#define OP_NET_DO_INIT_PROVIDER 1494
+#define OP_NET_DO_INIT_SESSION 1495
+#define OP_NET_DO_INIT_USER 1496
+#define OP_NET_QUERY_PROVIDERS 1497
+#define OP_NET_GET_PROVIDER_NAME 1498
+#define OP_NET_SET_PROVIDER 1499
+#define OP_NET_CLOSE_PROVIDER 1500
+#define OP_NET_QUERY_SESSIONS 1501
+#define OP_NET_GET_SESSION_NAME 1502
+#define OP_NET_CREATE_SESSION 1503
+#define OP_NET_JOIN_SESSION 1504
+#define OP_NET_END_SESSION 1505
+#define OP_NET_ADD_USER 1506
+#define OP_NET_REMOVE_USER 1507
+#define OP_NET_WHO_SENT_THIS 1508
+#define OP_NET_REMOTE_SEND_ARRAY 1509
+#define OP_NET_WHO_AM_I 1510
+#define OP_NET_REMOTE_START_FUNCTION 1511
+#define OP_NET_GET_PLAYER_LONG_NAME 1512
+#define OP_NET_GET_PLAYER_SHORT_NAME 1513
+#define OP_NET_SET_PROVIDER_BY_NAME 1516
+#define OP_NET_HOST_TCPIP_GAME 1517
+#define OP_NET_JOIN_TCPIP_GAME 1518
+#define OP_NET_SET_FAKE_LAG 1555
+#define OP_NET_GET_HOST_NAME 1556
+#define OP_NET_GET_IP_FROM_NAME 1557
+#define OP_NET_GET_SESSION_PLAYER_COUNT 1558
+#define OP_NET_DISABLE_SESSION_PLAYER_JOIN 1559
+#define OP_NET_START_QUERY_SESSIONS 1560
+#define OP_NET_UPDATE_QUERY_SESSIONS 1561
+#define OP_NET_STOP_QUERY_SESSIONS 1562
+#define OP_NET_DESTROY_PLAYER 1563
+#define OP_NET_ENABLE_SESSION_PLAYER_JOIN 1564
+#define OP_NET_SET_AI_PLAYER_COUNT 1565
+
+
+int32 LogicHEmoonbase::dispatch(int op, int numArgs, int32 *args) {
+ switch (op) {
+ case OP_CREATE_MULTI_STATE_WIZ:
+ op_create_multi_state_wiz(op, numArgs, args);
+ break;
+ case OP_LOAD_MULTI_CHANNEL_WIZ:
+ op_load_multi_channel_wiz(op, numArgs, args);
+ break;
+ case OP_WIZ_FROM_MULTI_CHANNEL_WIZ:
+ op_wiz_from_multi_channel_wiz(op, numArgs, args);
+ break;
+ case OP_DOS_COMMAND:
+ op_dos_command(op, numArgs, args);
+ break;
+ case OP_SET_FOW_SENTINEL:
+ op_set_fow_sentinel(args);
+ break;
+ case OP_SET_FOW_INFORMATION:
+ op_set_fow_information(op, numArgs, args);
+ break;
+ case OP_SET_FOW_IMAGE:
+ return op_set_fow_image(op, numArgs, args);
+
+ case OP_AI_TEST_KLUDGE:
+ op_ai_test_kludge(op, numArgs, args);
+ break;
+ case OP_AI_MASTER_CONTROL_PROGRAM:
+ return op_ai_master_control_program(op, numArgs, args);
+ case OP_AI_RESET:
+ op_ai_reset(op, numArgs, args);
+ break;
+ case OP_AI_SET_TYPE:
+ op_ai_set_type(op, numArgs, args);
+ break;
+ case OP_AI_CLEAN_UP:
+ op_ai_clean_up(op, numArgs, args);
+ break;
+
+ default:
+ LogicHE::dispatch(op, numArgs, args);
+ }
+
+ return 0;
+}
+
+void LogicHEmoonbase::op_create_multi_state_wiz(int op, int numArgs, int32 *args) {
+ warning("STUB: op_create_multi_state_wiz()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_load_multi_channel_wiz(int op, int numArgs, int32 *args) {
+ warning("STUB: op_load_multi_channel_wiz()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_wiz_from_multi_channel_wiz(int op, int numArgs, int32 *args) {
+ warning("STUB: op_wiz_from_multi_channel_wiz()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_dos_command(int op, int numArgs, int32 *args) {
+ warning("STUB: op_dos_command()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+void LogicHEmoonbase::op_set_fow_sentinel(int32 *args) {
+ debug(2, "op_set_fow_sentinel(%d, %d, %d)", args[0], args[1], args[2]);
+
+ _vm1->_moonbase->_fowSentinelImage = args[0];
+ _vm1->_moonbase->_fowSentinelState = args[1];
+ _vm1->_moonbase->_fowSentinelConditionBits = args[2];
+}
+
+void LogicHEmoonbase::op_set_fow_information(int op, int numArgs, int32 *args) {
+ Common::String str;
+
+ str = Common::String::format("op_set_fow_information(%d", args[0]);
+ for (int i = 1; i < numArgs; i++) {
+ str += Common::String::format(", %d", args[i]);
+ }
+ str += ")";
+
+ debug(2, "%s", str.c_str());
+
+ _vm1->_moonbase->setFOWInfo(
+ args[0], // array
+ args[1], // array down dimension
+ args[2], // array across dimension
+ args[3], // logical view X coordinate
+ args[4], // logical view Y coordinate
+ args[5], // screen draw clip rect x1
+ args[6], // screen draw clip rect y1
+ args[7], // screen draw clip rect x2
+ args[8], // screen draw clip rect y2
+ args[9], // techinque
+ args[10] // frame
+ );
+}
+
+int LogicHEmoonbase::op_set_fow_image(int op, int numArgs, int32 *args) {
+ debug(2, "op_set_fow_image(%d)", args[0]);
+ return _vm1->_moonbase->setFOWImage(args[0]) ? 1 : 0;
+}
+
+void LogicHEmoonbase::op_ai_test_kludge(int op, int numArgs, int32 *args) {
+ warning("STUB: op_ai_test_kludge()");
+ LogicHE::dispatch(op, numArgs, args);
+}
+
+int LogicHEmoonbase::op_ai_master_control_program(int op, int numArgs, int32 *args) {
+ warning("op_ai_master_control_program()");
+ return _vm1->_moonbase->_ai->masterControlProgram(numArgs, args);
+}
+
+void LogicHEmoonbase::op_ai_reset(int op, int numArgs, int32 *args) {
+ warning("op_ai_reset())");
+ _vm1->_moonbase->_ai->resetAI();
+}
+
+void LogicHEmoonbase::op_ai_set_type(int op, int numArgs, int32 *args) {
+ warning("op_ai_set_type()");
+ _vm1->_moonbase->_ai->setAIType(numArgs, args);
+}
+
+void LogicHEmoonbase::op_ai_clean_up(int op, int numArgs, int32 *args) {
+ warning("op_ai_clean_up()");
+ _vm1->_moonbase->_ai->cleanUpAI();
+}
+
+LogicHE *makeLogicHEmoonbase(ScummEngine_v100he *vm) {
+ return new LogicHEmoonbase(vm);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/logic_he.cpp b/engines/scumm/he/logic_he.cpp
index 366cd3be26..33f5c40464 100644
--- a/engines/scumm/he/logic_he.cpp
+++ b/engines/scumm/he/logic_he.cpp
@@ -102,7 +102,7 @@ LogicHE *LogicHE::makeLogicHE(ScummEngine_v90he *vm) {
return makeLogicHEbasketball(vm);
case GID_MOONBASE:
- return makeLogicHEmoonbase(vm);
+ return makeLogicHEmoonbase((ScummEngine_v100he *)vm);
default:
return new LogicHE(vm);
diff --git a/engines/scumm/he/logic_he.h b/engines/scumm/he/logic_he.h
index cd547f1616..5002ee9434 100644
--- a/engines/scumm/he/logic_he.h
+++ b/engines/scumm/he/logic_he.h
@@ -65,7 +65,7 @@ LogicHE *makeLogicHEfootball2002(ScummEngine_v90he *vm);
LogicHE *makeLogicHEsoccer(ScummEngine_v90he *vm);
LogicHE *makeLogicHEbaseball2001(ScummEngine_v90he *vm);
LogicHE *makeLogicHEbasketball(ScummEngine_v90he *vm);
-LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm);
+LogicHE *makeLogicHEmoonbase(ScummEngine_v100he *vm);
} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
new file mode 100644
index 0000000000..ab61297603
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -0,0 +1,767 @@
+/* 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.
+ *
+ */
+
+#include "common/rect.h"
+#include "common/util.h"
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_defenseunit.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+DefenseUnit::DefenseUnit(AI *ai) : _ai(ai) {
+ _state = DUS_ON;
+
+ _id = -1;
+ _distanceTo = 0;
+ _state = 0;
+ _radius = 0;
+ _armor = 0;
+ _cost = 0;
+}
+
+DefenseUnit::DefenseUnit(DefenseUnit *inUnit, AI *ai) : _ai(ai) {
+ _id = inUnit->getID();
+ _pos.x = inUnit->getPosX();
+ _pos.y = inUnit->getPosY();
+ _distanceTo = inUnit->getDistanceTo();
+ _state = inUnit->getState();
+ _radius = inUnit->getRadius();
+ _armor = inUnit->getArmor();
+ _cost = inUnit->getCost();
+}
+
+DefenseUnit::~DefenseUnit() {
+}
+
+Common::Point *AntiAirUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ float ratio;
+ int radius;
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ radius = getRadius();
+
+ if ((distance < radius) || (getState() == DUS_OFF)) {
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ } else {
+ ratio = MAX(0, (getRadius() / distance));
+ targetPos->x = (int16)(getPosX() - ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(getPosY() - ratio * (getPosY() - sourceY));
+ }
+
+ break;
+
+ case ITEM_EMP:
+ if (getRadius() + 215 > distance) { // Emp radius
+ double x1 = static_cast<double>(sourceX);
+ double y1 = static_cast<double>(sourceY);
+ double x2 = static_cast<double>(getPosX());
+ double y2 = static_cast<double>(getPosY());
+ double r1 = static_cast<double>(215);
+ double r2 = static_cast<double>(getRadius() + 3);
+ double d = static_cast<double>(distance);
+
+ // Formulae for calculating one point of intersection of two circles
+ float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
+ int x = (int)(((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root);
+ int y = (int)(((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root);
+
+ targetPos->x = x;
+ targetPos->y = y;
+ } else {
+ ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
+ }
+
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int AntiAirUnit::selectWeapon(int index) {
+ switch (index) {
+ case 0:
+ return ITEM_CLUSTER;
+ break;
+
+ case 1:
+ return ITEM_EMP;
+ break;
+
+ case 2:
+ if (getState() == DUS_OFF) {
+ if (_ai->getPlayerEnergy() > 6) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
+ return ITEM_VIRUS;
+ }
+ }
+
+ if (_ai->getPlayerEnergy() > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(1)) {
+ return ITEM_SPIKE;
+ }
+ }
+
+ return ITEM_BOMB;
+ }
+
+ return ITEM_CLUSTER;
+ break;
+
+ default:
+ return ITEM_CLUSTER;
+ break;
+ }
+}
+
+Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ float ratio;
+ Common::Point *targetPos = new Common::Point;
+
+ if (getState() == DUS_OFF) {
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ } else {
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ ratio = MAX(0.0, 1.0 - (static_cast<float>(getRadius()) / static_cast<float>(distance - 20)));
+ {
+ int maxX = _ai->getMaxX();
+ int maxY = _ai->getMaxY();
+ int thisX = (static_cast<int>(sourceX + ratio * (getPosX() - sourceX)) + maxX) % maxX;
+ int thisY = (static_cast<int>(sourceY + ratio * (getPosY() - sourceY)) + maxY) % maxY;
+ targetPos->x = thisX;
+ targetPos->y = thisY;
+ }
+ break;
+
+ case ITEM_EMP:
+ if (getRadius() + 215 > distance) { // Emp radius
+ double x1 = static_cast<double>(sourceX);
+ double y1 = static_cast<double>(sourceY);
+ double x2 = static_cast<double>(getPosX());
+ double y2 = static_cast<double>(getPosY());
+ double r1 = static_cast<double>(215);
+ double r2 = static_cast<double>(getRadius() + 10);
+ double d = static_cast<double>(distance);
+
+ // Formulae for calculating one point of intersection of two circles
+ float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
+ int x = (int)(((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root);
+ int y = (int)(((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root);
+
+ targetPos->x = x;
+ targetPos->y = y;
+ } else {
+ ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
+ }
+
+ if (distance < getRadius()) {
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ }
+
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+ }
+
+ return targetPos;
+}
+
+int ShieldUnit::selectWeapon(int index) {
+ warning("Shield weapon select");
+
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+ int dist = _ai->getDistance(getPosX(), getPosY(), _ai->getHubX(myUnit), _ai->getHubY(myUnit));
+
+ if ((dist < (getRadius() - 20)) && (dist > 90)) {
+ return ITEM_SPIKE;
+ }
+
+ switch (index) {
+ case 0:
+ if (getState() == DUS_OFF) {
+ if (_ai->getPlayerEnergy() < 3) {
+ return ITEM_BOMB;
+ } else {
+ return ITEM_SPIKE;
+ }
+ }
+
+ return ITEM_EMP;
+ break;
+
+ case 1:
+ if (dist < getRadius() + 150) {
+ return ITEM_EMP;
+ } else {
+ return ITEM_CRAWLER;
+ }
+
+ break;
+
+ default:
+ return ITEM_EMP;
+ break;
+ }
+}
+
+Common::Point *MineUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ float ratio;
+ Common::Point *targetPos = new Common::Point;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_EMP:
+ ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+ targetPos->x = (int16)(sourceX + ratio * (getPosX() - sourceX));
+ targetPos->y = (int16)(sourceY + ratio * (getPosY() - sourceY));
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int MineUnit::selectWeapon(int index) {
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, 0, 0, 0);
+ int x = getPosX();
+ int y = getPosY();
+
+ int dist = _ai->getDistance(x, y, _ai->getHubX(myUnit), _ai->getHubY(myUnit));
+
+ if ((getState() == DUS_ON) && (dist < 110)) {
+ return ITEM_EMP;
+ } else {
+ return ITEM_BOMB;
+ }
+}
+
+
+Common::Point *HubUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int HubUnit::selectWeapon(int index) {
+ warning("Hub weapon select");
+
+ int energy = _ai->getPlayerEnergy();
+
+ if (energy > 6) {
+ //possibly choose crawler
+ if (_ai->getBuildingWorth(getID()) > 21) {
+ return ITEM_CRAWLER;
+ }
+ }
+
+ //choose betw/ bomb and cluster
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
+ return ITEM_CLUSTER;
+ }
+
+ if (energy > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
+ return ITEM_SPIKE;
+ }
+
+ if (!_ai->_vm->_rnd.getRandomNumber(4)) {
+ return ITEM_GUIDED;
+ }
+
+ if (!_ai->_vm->_rnd.getRandomNumber(4)) {
+ return ITEM_MINE;
+ }
+
+ if (!_ai->_vm->_rnd.getRandomNumber(9)) {
+ return ITEM_EMP;
+ }
+ }
+
+ return ITEM_BOMB;
+}
+
+
+Common::Point *TowerUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_SPIKE:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int TowerUnit::selectWeapon(int index) {
+ switch (index) {
+ case 0:
+ return ITEM_SPIKE;
+ break;
+
+ default:
+ return ITEM_SPIKE;
+ break;
+ }
+}
+
+
+Common::Point *BridgeUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int BridgeUnit::selectWeapon(int index) {
+ switch (index) {
+ case 0:
+ return ITEM_BOMB;
+ break;
+
+ case 1:
+ return ITEM_CLUSTER;
+ break;
+
+ default:
+ return ITEM_BOMB;
+ break;
+ }
+}
+
+Common::Point *EnergyUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int EnergyUnit::selectWeapon(int index) {
+ warning("Energy weapon select");
+
+ int energy = _ai->getPlayerEnergy();
+
+ if (energy > 6) {
+ //possibly choose crawler
+ if (_ai->getBuildingWorth(getID()) > 21) {
+ return ITEM_CRAWLER;
+ }
+ }
+
+ //choose betw/ bomb and cluster
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
+ return ITEM_CLUSTER;
+ }
+
+ if (energy > 2) {
+ if (!_ai->_vm->_rnd.getRandomNumber(3)) {
+ return ITEM_EMP;
+ }
+ }
+
+ return ITEM_BOMB;
+}
+
+Common::Point *OffenseUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance) distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int OffenseUnit::selectWeapon(int index) {
+ warning("Offense weapon select");
+
+ int energy = _ai->getPlayerEnergy();
+
+ if (energy > 6) {
+ //possibly choose crawler
+ if (_ai->getBuildingWorth(getID()) > 21) {
+ return ITEM_CRAWLER;
+ }
+ }
+
+ //choose betw/ bomb and cluster
+ if (_ai->getBuildingArmor(getID()) < 1.5) {
+ return ITEM_CLUSTER;
+ }
+
+ return ITEM_BOMB;
+}
+
+Common::Point *CrawlerUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+ Common::Point *targetPos = new Common::Point;
+
+ if (!distance)
+ distance = 1;
+
+ switch (weaponType) {
+ case ITEM_BOMB:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CLUSTER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ case ITEM_CRAWLER:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+
+ default:
+ targetPos->x = getPosX();
+ targetPos->y = getPosY();
+ break;
+ }
+
+ return targetPos;
+}
+
+int CrawlerUnit::selectWeapon(int index) {
+ warning("Crawler weapon select");
+ int myUnit = _ai->getClosestUnit(getPosX(), getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, 0, 0, 0);
+ int dist = _ai->getDistance(_ai->getHubX(myUnit), _ai->getHubY(myUnit), getPosX(), getPosY());
+
+ int x = getPosX();
+ int y = getPosY();
+ int energy = _ai->getPlayerEnergy();
+ int terrain = _ai->getTerrain(x, y);
+
+ if (terrain != TERRAIN_TYPE_WATER) {
+ if ((energy > 2) && (dist < 220)) {
+ return ITEM_RECLAIMER;
+ } else {
+ return ITEM_BOMB;
+ }
+ } else {
+ if (energy > 6) {
+ return ITEM_CRAWLER;
+ }
+
+ if (energy > 2) {
+ if (_ai->_vm->_rnd.getRandomNumber(1)) {
+ return ITEM_MINE;
+ } else {
+ return ITEM_TIME_EXPIRED;
+ }
+ }
+ }
+
+ return SKIP_TURN;
+}
+
+AntiAirUnit::AntiAirUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(190);
+ setArmor(3);
+ setCost(1);
+}
+
+ShieldUnit::ShieldUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(170);
+ setArmor(3);
+ setCost(7);
+}
+
+MineUnit::MineUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(80);
+ setArmor(1);
+ setCost(3);
+}
+
+HubUnit::HubUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(5);
+ setCost(7);
+}
+
+TowerUnit::TowerUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(1);
+}
+
+BridgeUnit::BridgeUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(1);
+}
+
+EnergyUnit::EnergyUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(5);
+ setCost(7);
+}
+
+OffenseUnit::OffenseUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(7);
+}
+
+CrawlerUnit::CrawlerUnit(AI *ai) : DefenseUnit(ai) {
+ setRadius(1);
+ setArmor(3);
+ setCost(7);
+}
+
+AntiAirUnit::AntiAirUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+
+}
+
+ShieldUnit::ShieldUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+MineUnit::MineUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+HubUnit::HubUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+TowerUnit::TowerUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+BridgeUnit::BridgeUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+EnergyUnit::EnergyUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+OffenseUnit::OffenseUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+CrawlerUnit::CrawlerUnit(DefenseUnit *inUnit, AI *ai) : DefenseUnit(inUnit, ai) {
+ setID(inUnit->getID());
+ setPos(inUnit->getPosX(), inUnit->getPosY());
+ setDistanceTo(inUnit->getDistanceTo());
+ setState(inUnit->getState());
+ setRadius(inUnit->getRadius());
+ setArmor(inUnit->getArmor());
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.h b/engines/scumm/he/moonbase/ai_defenseunit.h
new file mode 100644
index 0000000000..a6085da859
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_defenseunit.h
@@ -0,0 +1,195 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_DEFENCEUNIT_H
+#define SCUMM_HE_MOONBASE_AI_DEFENCEUNIT_H
+
+namespace Scumm {
+
+class AI;
+
+enum {
+ DUT_ANTI_AIR = 1,
+ DUT_SHIELD = 2,
+ DUT_MINE = 3,
+ DUT_HUB = 4,
+ DUT_TOWER = 5,
+ DUT_BRIDGE = 6,
+ DUT_ENERGY = 7,
+ DUT_OFFENSE = 8,
+ DUT_CRAWLER = 9
+};
+
+enum {
+ DUS_ON = 1,
+ DUS_OFF = 2,
+ DUS_DESTROYED = 3
+};
+
+class DefenseUnit {
+private:
+ int _id;
+ Common::Point _pos;
+ int _distanceTo;
+ int _state;
+ int _radius;
+ int _armor;
+ int _cost;
+
+protected:
+ AI *_ai;
+
+public:
+ DefenseUnit(AI *ai);
+ DefenseUnit(DefenseUnit *inUnit, AI *ai);
+
+ virtual ~DefenseUnit();
+
+ void setID(int id) { _id = id; }
+ void setDistanceTo(int distanceTo) { _distanceTo = distanceTo; }
+ void setState(int state) { _state = state; }
+ void setRadius(int radius) { _radius = radius; }
+ void setArmor(int armor) { _armor = armor; }
+ void setDamage(int damage) { _armor -= damage; }
+ void setPos(int x, int y) {
+ _pos.x = x;
+ _pos.y = y;
+ }
+ void setCost(int cost) { _cost = cost; }
+
+ int getID() const { return _id; }
+ int getDistanceTo() const { return _distanceTo; }
+ int getState() const { return _state; }
+ int getRadius() const { return _radius; }
+ int getArmor() const { return _armor; }
+ int getPosX() const { return _pos.x; }
+ int getPosY() const { return _pos.y; }
+ int getCost() const { return _cost; }
+
+ virtual int getType() const = 0;
+
+ virtual Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) = 0;
+ virtual int selectWeapon(int index) = 0;
+};
+
+class AntiAirUnit : public DefenseUnit {
+private:
+
+public:
+ AntiAirUnit(AI *ai);
+ AntiAirUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_ANTI_AIR; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class ShieldUnit : public DefenseUnit {
+private:
+
+public:
+ ShieldUnit(AI *ai);
+ ShieldUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_SHIELD; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class MineUnit : public DefenseUnit {
+private:
+
+public:
+ MineUnit(AI *ai);
+ MineUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_MINE; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class HubUnit : public DefenseUnit {
+private:
+
+public:
+ HubUnit(AI *ai);
+ HubUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_HUB; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class TowerUnit : public DefenseUnit {
+private:
+
+public:
+ TowerUnit(AI *ai);
+ TowerUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_TOWER; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class BridgeUnit : public DefenseUnit {
+private:
+
+public:
+ BridgeUnit(AI *ai);
+ BridgeUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_BRIDGE; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class EnergyUnit : public DefenseUnit {
+private:
+
+public:
+ EnergyUnit(AI *ai);
+ EnergyUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_ENERGY; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class OffenseUnit : public DefenseUnit {
+private:
+
+public:
+ OffenseUnit(AI *ai);
+ OffenseUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_OFFENSE; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+class CrawlerUnit : public DefenseUnit {
+private:
+
+public:
+ CrawlerUnit(AI *ai);
+ CrawlerUnit(DefenseUnit *inUnit, AI *ai);
+ int getType() const { return DUT_CRAWLER; }
+ Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+ int selectWeapon(int index);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_main.cpp b/engines/scumm/he/moonbase/ai_main.cpp
new file mode 100644
index 0000000000..98a577bdba
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_main.cpp
@@ -0,0 +1,3067 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/ai_traveller.h"
+#include "scumm/he/moonbase/ai_targetacquisition.h"
+#include "scumm/he/moonbase/ai_types.h"
+#include "scumm/he/moonbase/ai_pattern.h"
+
+namespace Scumm {
+
+enum {
+ F_GET_SCUMM_DATA = 0,
+ F_GET_WORLD_DIST = 1,
+ F_GET_WORLD_ANGLE = 2,
+ F_GET_TERRAIN_TYPE = 3,
+ F_GET_CLOSEST_UNIT = 4,
+ F_SIMULATE_BUILDING_LAUNCH = 5,
+ F_GET_POWER_ANGLE_FROM_POINT = 6,
+ F_CHECK_IF_WATER_STATE = 7,
+ F_GET_UNITS_WITHIN_RADIUS = 8,
+ F_GET_LANDING_POINT = 9,
+ F_GET_ENEMY_UNITS_VISIBLE = 10,
+ F_CHECK_IF_WATER_SQUARE = 11,
+ F_GET_GROUND_ALTITUDE = 12,
+ F_CHECK_FOR_CORD_OVERLAP = 13,
+ F_CHECK_FOR_ANGLE_OVERLAP = 14,
+ F_ESTIMATE_NEXT_ROUND_ENERGY = 15,
+ F_CHECK_FOR_UNIT_OVERLAP = 16,
+ F_GET_COORDINATE_VISIBILITY = 17,
+ F_CHECK_FOR_ENERGY_SQUARE = 18,
+ F_AI_CHAT = 19
+};
+
+enum {
+ D_GET_HUB_X = 1,
+ D_GET_HUB_Y = 2,
+ D_GET_WORLD_X_SIZE = 3,
+ D_GET_WORLD_Y_SIZE = 4,
+ D_GET_CURRENT_PLAYER = 5,
+ D_GET_MAX_POWER = 6,
+ D_GET_MIN_POWER = 7,
+ D_GET_TERRAIN_SQUARE_SIZE = 8,
+ D_GET_BUILDING_OWNER = 9,
+ D_GET_BUILDING_STATE = 10,
+ D_GET_BUILDING_TYPE = 11,
+ D_DEBUG_BREAK = 12,
+ D_GET_ENERGY_POOLS_ARRAY = 13,
+ D_GET_COORDINATE_VISIBILITY = 14,
+ D_GET_UNIT_VISIBILITY = 15,
+ D_GET_ENERGY_POOL_VISIBILITY = 16,
+ D_GET_NUMBER_OF_POOLS = 17,
+ D_GET_NUMBER_OF_PLAYERS = 18,
+ D_GET_BUILDING_ARMOR = 19,
+ D_GET_BUILDING_WORTH = 20,
+ D_GET_PLAYER_ENERGY = 21,
+ D_GET_PLAYER_MAX_TIME = 22,
+ D_GET_WIND_X_SPEED = 23,
+ D_GET_WIND_Y_SPEED = 24,
+ D_GET_TOTAL_WIND_SPEED = 25,
+ D_GET_WIND_X_SPEED_MAX = 26,
+ D_GET_WIND_Y_SPEED_MAX = 27,
+ D_GET_BIG_X_SIZE = 28,
+ D_GET_BIG_Y_SIZE = 29,
+ D_GET_ENERGY_POOL_WIDTH = 30,
+ D_GET_BUILDING_MAX_ARMOR = 31,
+ D_GET_TIMER_VALUE = 32,
+ D_GET_LAST_ATTACKED_X = 33,
+ D_GET_LAST_ATTACKED_Y = 34,
+ D_PRINT_DEBUG_TIMER = 35,
+ D_GET_PLAYER_TEAM = 36,
+ D_GET_BUILDING_TEAM = 37,
+ D_GET_FOW = 38,
+ D_GET_ANIM_SPEED = 39,
+ D_GET_BUILDING_STACK_PTR = 40,
+ D_GET_TURN_COUNTER = 41
+};
+
+enum {
+ AI_TYPE_PLAYER_NUM = 0,
+ AI_TYPE_TYPE = 1
+};
+
+enum {
+ ENERGY_MODE = 0,
+ OFFENSE_MODE = 1,
+ DEFENSE_MODE = 2
+};
+
+enum {
+ LAUNCH_SOURCE_HUB = 0,
+ LAUNCH_UNIT = 1,
+ LAUNCH_ANGLE = 2,
+ LAUNCH_POWER = 3,
+
+ MAX_LAUNCH_POWER = 560,
+ MAX_FIRING_DISTANCE = 560
+};
+
+enum {
+ SCALE_X = 50,
+ SCALE_Y = 50,
+ SCALE_Z = 50,
+
+ GRAVITY_CONSTANT = (MAX_LAUNCH_POWER *MAX_LAUNCH_POWER) / MAX_FIRING_DISTANCE,
+
+ HEIGHT_LOW = 20,
+
+ NODE_RADIUS = 7,
+ NODE_DIAMETER = NODE_RADIUS * 2 + 2,
+ NODE_DETECT_RADIUS = NODE_RADIUS - 1,
+
+ BUILDING_HUB_RADIUS = 16
+};
+
+enum {
+ STATE_CHOOSE_BEHAVIOR = 0,
+ STATE_CHOOSE_TARGET = 1,
+ STATE_ATTEMPT_SEARCH = 2,
+ STATE_INIT_APPROACH_TARGET = 3,
+ STATE_APPROACH_TARGET = 4,
+ STATE_INIT_ACQUIRE_TARGET = 5,
+ STATE_ACQUIRE_TARGET = 6,
+ STATE_ENERGIZE_TARGET = 7,
+ STATE_OFFEND_TARGET = 8,
+ STATE_DEFEND_TARGET = 9,
+ STATE_LAUNCH = 10,
+ STATE_CRAWLER_DECISION = 11,
+
+ TREE_DEPTH = 2
+};
+
+AI::AI(ScummEngine_v100he *vm) : _vm(vm) {
+ memset(_aiType, 0, sizeof(_aiType));
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+ _behavior = 2;
+ _energyHogType = 0;
+
+ memset(_moveList, 0, sizeof(_moveList));
+ _mcpParams = 0;
+}
+
+void AI::resetAI() {
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+ warning("----------------------> Resetting AI");
+
+ for (int i = 1; i != 5; i++) {
+ if (_aiType[i]) {
+ delete _aiType[i];
+ _aiType[i] = NULL;
+ }
+
+ _aiType[i] = new AIEntity(BRUTAKAS);
+ }
+
+ for (int i = 1; i != 5; i++) {
+ if (_moveList[i]) {
+ delete _moveList[i];
+ _moveList[i] = NULL;
+ }
+
+ _moveList[i] = new patternList;
+ }
+}
+
+void AI::cleanUpAI() {
+ warning("----------------------> Cleaning Up AI");
+
+ for (int i = 1; i != 5; i++) {
+ if (_aiType[i]) {
+ delete _aiType[i];
+ _aiType[i] = NULL;
+ }
+ }
+
+ for (int i = 1; i != 5; i++) {
+ if (_moveList[i]) {
+ delete _moveList[i];
+ _moveList[i] = NULL;
+ }
+ }
+}
+
+void AI::setAIType(const int paramCount, const int32 *params) {
+ if (_aiType[params[AI_TYPE_PLAYER_NUM]]) {
+ delete _aiType[params[AI_TYPE_PLAYER_NUM]];
+ _aiType[params[AI_TYPE_PLAYER_NUM]] = NULL;
+ }
+
+ _aiType[params[AI_TYPE_PLAYER_NUM]] = new AIEntity(params[AI_TYPE_TYPE]);
+
+ if (params[AI_TYPE_TYPE] == ENERGY_HOG) {
+ _energyHogType = 1;
+ } else {
+ _energyHogType = 0;
+ }
+
+ warning("AI for player %d is %s", params[AI_TYPE_PLAYER_NUM], _aiType[params[AI_TYPE_PLAYER_NUM]]->getNameString());
+}
+
+int AI::masterControlProgram(const int paramCount, const int32 *params) {
+ static Tree *myTree;
+
+ static int index;
+
+ _mcpParams = params;
+
+ static int lastSource[5];
+ static int lastAngle[5];
+ static int lastPower[5];
+
+
+ static int sourceHub;
+ static int target;
+
+ static int targetX;
+ static int targetY;
+
+ static int _acquireTarget = 0;
+
+ static int *launchAction = NULL;
+ static int *currentLaunchAction = NULL;
+
+ static int OLflag = 0;
+ static int TAflag = 0;
+
+
+ Node *retNode;
+ static int retNodeFlag;
+
+ // Memory cleanup in case of quit during game
+ if (_vm->readVar(_vm->VAR_U32_USER_VAR_F)) {
+ if (myTree != NULL) {
+ delete myTree;
+ myTree = NULL;
+ }
+
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ if (currentLaunchAction != NULL) {
+ delete currentLaunchAction;
+ currentLaunchAction = NULL;
+ }
+
+ return 1;
+ }
+
+ int currentPlayer = getCurrentPlayer();
+
+ int maxTime = getPlayerMaxTime();
+ int timerValue = getTimerValue(3);
+
+ // If timer has run out
+ if ((_aiState > STATE_CHOOSE_BEHAVIOR) && ((maxTime) && (timerValue > maxTime))) {
+ if (myTree != NULL) {
+ delete myTree;
+ myTree = NULL;
+ }
+
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ launchAction = new int[4];
+
+ if (currentLaunchAction != NULL) {
+ launchAction[LAUNCH_SOURCE_HUB] = currentLaunchAction[LAUNCH_SOURCE_HUB];
+ launchAction[LAUNCH_UNIT] = currentLaunchAction[LAUNCH_UNIT];
+ launchAction[LAUNCH_ANGLE] = currentLaunchAction[LAUNCH_ANGLE];
+ launchAction[LAUNCH_POWER] = currentLaunchAction[LAUNCH_POWER];
+ delete currentLaunchAction;
+ currentLaunchAction = NULL;
+ } else {
+ if (!_vm->_rnd.getRandomNumber(1))
+ launchAction[1] = ITEM_TIME_EXPIRED;
+ else
+ launchAction[1] = SKIP_TURN;
+ }
+
+ _aiState = STATE_LAUNCH;
+ }
+
+ static int old_aiState = 0;
+
+ if (old_aiState != _aiState) {
+ warning("<<%d>>", _aiState);
+ old_aiState = _aiState;
+ }
+
+ switch (_aiState) {
+ case STATE_CHOOSE_BEHAVIOR:
+ _behavior = chooseBehavior();
+ warning("Behavior mode: %d", _behavior);
+
+ if ((int)_vm->_rnd.getRandomNumber(99) < _aiType[getCurrentPlayer()]->getBehaviorVariation() * AI_VAR_BASE_BEHAVIOR + 1) {
+ if (_vm->_rnd.getRandomNumber(1)) {
+ _behavior--;
+
+ if (_behavior < ENERGY_MODE)
+ _behavior = DEFENSE_MODE;
+ } else {
+ _behavior++;
+
+ if (_behavior > DEFENSE_MODE)
+ _behavior = ENERGY_MODE;
+ }
+
+ warning("Alternative behavior: %d", _behavior);
+ }
+
+ if (_behavior == ENERGY_MODE)
+ if (!getNumberOfPools())
+ _behavior = OFFENSE_MODE;
+
+ if (_aiType[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER)
+ _behavior = OFFENSE_MODE;
+
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ index = 0;
+ _aiState = STATE_CHOOSE_TARGET;
+ break;
+
+ case STATE_CHOOSE_TARGET:
+ target = chooseTarget(_behavior);
+
+ if (!target)
+ target = chooseTarget(OFFENSE_MODE);
+
+ if (_behavior == ENERGY_MODE) {
+ int energyPoolScummArray = getEnergyPoolsArray();
+ targetX = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_X);
+ targetY = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_Y);
+ } else {
+ targetX = getHubX(target);
+ targetY = getHubY(target);
+ }
+
+ warning("Target (%d, %d) id: %d", targetX, targetY, target);
+
+ if (getFOW())
+ _aiState = STATE_ATTEMPT_SEARCH;
+ else
+ _aiState = STATE_INIT_APPROACH_TARGET;
+
+ break;
+
+ case STATE_ATTEMPT_SEARCH:
+ if (!getCoordinateVisibility(targetX, targetY, currentPlayer)) {
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+ int targetAngle = calcAngle(getHubX(closestHub), getHubY(closestHub), targetX, targetY);
+ int testX = static_cast<int>(getHubX(closestHub) + (500 * cos(degToRad(targetAngle))) + getMaxX()) % getMaxX();
+ int testY = static_cast<int>(getHubY(closestHub) + (500 * sin(degToRad(targetAngle))) + getMaxY()) % getMaxY();
+
+ int balloonFlag = 0;
+
+ int unitsArray = getUnitsWithinRadius(testX, testY, 500);
+ int unitsCounter = 0;
+
+ //see if any balloons are already in the area
+ int nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
+
+ while (nextBuilding) {
+ if (((getBuildingType(nextBuilding) == BUILDING_BALLOON) || (getBuildingType(nextBuilding) == BUILDING_TOWER)) && (getBuildingTeam(nextBuilding) == getPlayerTeam(currentPlayer))) {
+ balloonFlag = 1;
+ nextBuilding = 0;
+ continue;
+ }
+
+ unitsCounter++;
+ nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(unitsArray);
+
+ if (!balloonFlag) {
+ launchAction = new int[4];
+ launchAction[LAUNCH_SOURCE_HUB] = closestHub;
+
+ if (getPlayerEnergy() > 3) {
+ launchAction[LAUNCH_UNIT] = ITEM_BALLOON;
+ launchAction[LAUNCH_POWER] = getMaxPower();
+ } else {
+ launchAction[LAUNCH_UNIT] = ITEM_TOWER;
+ launchAction[LAUNCH_POWER] = getMinPower();
+ }
+
+ launchAction[LAUNCH_ANGLE] = targetAngle + (_vm->_rnd.getRandomNumber(89) - 45);
+
+ int newTargetPos = abs(fakeSimulateWeaponLaunch(getHubX(closestHub), getHubY(closestHub), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]));
+ targetX = newTargetPos % getMaxX();
+ targetY = newTargetPos / getMaxY();
+
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ break;
+ }
+ }
+
+ _aiState = STATE_INIT_APPROACH_TARGET;
+ break;
+
+ case STATE_INIT_APPROACH_TARGET:
+ {
+ int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1);
+
+ if (closestOL && (_behavior == OFFENSE_MODE)) {
+ _aiState = STATE_OFFEND_TARGET;
+ break;
+ }
+ }
+
+ // get closest hub...if attack mode and almost close enough, maybe throw an offense
+ if ((_behavior == OFFENSE_MODE) && (getPlayerEnergy() > 6)) {
+ if (!_vm->_rnd.getRandomNumber(2)) {
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
+
+ if ((dist > 470) && (dist < 900)) {
+ int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 0);
+
+ if (!closestOL) {
+ // Launch an OL
+ OLflag = 1;
+ targetX = getHubX(closestHub);
+ targetY = getHubY(closestHub);
+
+ _aiState = STATE_DEFEND_TARGET;
+ break;
+ }
+ }
+ }
+ }
+
+ if ((_behavior == OFFENSE_MODE) && (_aiType[currentPlayer]->getID() == RANGER) && (getPlayerEnergy() > 2)) {
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
+
+ if (dist < 750) {
+ _aiState = STATE_OFFEND_TARGET;
+ break;
+ }
+ }
+
+ myTree = initApproachTarget(targetX, targetY, &retNode);
+
+ // If no need to approach, apply appropriate behavior
+ if (retNode == myTree->getBaseNode()) {
+ switch (_behavior) {
+ case 0:
+ _aiState = STATE_ENERGIZE_TARGET;
+ break;
+
+ case 1:
+ _aiState = STATE_OFFEND_TARGET;
+ break;
+
+ case 2:
+ _aiState = STATE_DEFEND_TARGET;
+ break;
+
+ case -1:
+ _aiState = STATE_LAUNCH;
+ break;
+ }
+
+ delete myTree;
+ myTree = NULL;
+ break;
+ }
+
+ delete retNode;
+ retNode = NULL;
+
+ if (getPlayerEnergy() < 7) {
+ if (!_vm->_rnd.getRandomNumber(3)) {
+ _behavior = DEFENSE_MODE;
+ _aiState = STATE_CHOOSE_TARGET;
+ } else {
+ if (launchAction == NULL) {
+ launchAction = new int[4];
+ }
+
+ if (!_vm->_rnd.getRandomNumber(2)) {
+ launchAction[1] = ITEM_TIME_EXPIRED;
+ } else {
+ launchAction[1] = SKIP_TURN;
+ }
+
+ _aiState = STATE_LAUNCH;
+ }
+
+ delete myTree;
+ myTree = NULL;
+ break;
+ }
+
+ _aiState = STATE_CRAWLER_DECISION;
+ break;
+
+ // If behavior is offense, possibly just chuck a crawler
+ case STATE_CRAWLER_DECISION:
+ {
+ // Brace just here to scope throwCrawler
+ int throwCrawler = 0;
+
+ if (_behavior == OFFENSE_MODE) {
+ if (getPlayerEnergy() > 6) {
+ int crawlerTest = _vm->_rnd.getRandomNumber(9);
+
+ if (!crawlerTest)
+ throwCrawler = 1;
+ }
+ }
+
+ if (_aiType[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER) {
+ if (getPlayerEnergy() > 6) {
+ throwCrawler = 1;
+ } else {
+ launchAction = new int[4];
+
+ if (!_vm->_rnd.getRandomNumber(1))
+ launchAction[1] = ITEM_TIME_EXPIRED;
+ else
+ launchAction[1] = SKIP_TURN;
+
+ _aiState = STATE_LAUNCH;
+ delete myTree;
+ myTree = NULL;
+ }
+ }
+
+ if (throwCrawler) {
+ sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
+ int powAngle = getPowerAngleFromPoint(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY, 15);
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ launchAction = new int[4];
+ launchAction[0] = sourceHub;
+ launchAction[1] = ITEM_CRAWLER;
+ warning("CRAWLER DECISION is launching a crawler");
+ launchAction[2] = angle;
+ launchAction[3] = power;
+ retNodeFlag = 0;
+
+ // Need to update target so acquire can work
+ int targetCoords = fakeSimulateWeaponLaunch(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]);
+ targetX = targetCoords % getMaxX();
+ targetY = targetCoords / getMaxX();
+ targetX = (targetX + getMaxX()) % getMaxX();
+ targetY = (targetY + getMaxY()) % getMaxY();
+
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ delete myTree;
+ myTree = NULL;
+ } else {
+ _aiState = STATE_APPROACH_TARGET;
+ }
+ break;
+ }
+
+ // ApproachTarget returns NULL if target is already reachable
+ case STATE_APPROACH_TARGET:
+ {
+ int x, y;
+ Node *currentNode = NULL;
+ launchAction = approachTarget(myTree, x, y, &currentNode);
+ }
+
+ if (launchAction != NULL) {
+ if (launchAction[0] == -1) {
+ warning("Creating fake target approach hub");
+ TAflag = 1;
+ int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ targetX = getHubX(closestHub);
+ targetY = getHubY(closestHub);
+
+ delete[] launchAction;
+ launchAction = NULL;
+ _aiState = STATE_DEFEND_TARGET;
+ delete myTree;
+ myTree = NULL;
+ break;
+ }
+
+ // Need to update target so acquire can work
+ int targetCoords = fakeSimulateWeaponLaunch(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]);
+ targetX = targetCoords % getMaxX();
+ targetY = targetCoords / getMaxX();
+ targetX = (targetX + getMaxX()) % getMaxX();
+ targetY = (targetY + getMaxY()) % getMaxY();
+
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ _behavior = -1;
+
+ delete myTree;
+ myTree = NULL;
+ }
+
+ break;
+
+ case STATE_ENERGIZE_TARGET:
+ launchAction = energizeTarget(targetX, targetY, index);
+
+ if (launchAction != NULL) {
+ if (launchAction[0]) {
+ assert(launchAction[0] > 0);
+
+ if (launchAction[1] == ITEM_HUB) {
+ index = 0;
+ retNodeFlag = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ } else {
+ index = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ }
+ } else {
+ index++;
+ delete[] launchAction;
+ launchAction = NULL;
+ }
+ } else {
+ _behavior = DEFENSE_MODE;
+ retNodeFlag = 0;
+ index = 0;
+ _aiState = STATE_CHOOSE_TARGET;
+ }
+ break;
+
+ case STATE_OFFEND_TARGET:
+ launchAction = offendTarget(targetX, targetY, index);
+
+ if (launchAction != NULL) {
+ if (launchAction[0]) {
+ retNodeFlag = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+ } else {
+ index++;
+ delete[] launchAction;
+ launchAction = NULL;
+ }
+ }
+ break;
+
+ case STATE_DEFEND_TARGET:
+ launchAction = defendTarget(targetX, targetY, index);
+
+ if (launchAction != NULL) {
+ if (launchAction[0]) {
+ retNodeFlag = 0;
+ _aiState = STATE_INIT_ACQUIRE_TARGET;
+
+ if (launchAction[LAUNCH_UNIT] != ITEM_BRIDGE) {
+ if (OLflag) {
+ OLflag = 0;
+ launchAction[LAUNCH_UNIT] = ITEM_OFFENSE;
+ }
+
+ if (TAflag) {
+ TAflag = 0;
+ warning("replacing defense unit %d with a hub", launchAction[LAUNCH_UNIT]);
+ launchAction[LAUNCH_UNIT] = ITEM_HUB;
+ }
+ }
+ } else {
+ index++;
+ delete[] launchAction;
+ launchAction = NULL;
+ }
+ }
+ break;
+
+ case STATE_INIT_ACQUIRE_TARGET:
+ myTree = initAcquireTarget(targetX, targetY, &retNode);
+
+ if (myTree == NULL) {
+ _aiState = STATE_LAUNCH;
+ break;
+ }
+
+ // This next line is a questionable fix
+ if (retNode == myTree->getBaseNode())
+ retNodeFlag = 1;
+
+ _acquireTarget = 0;
+
+ _aiState = STATE_ACQUIRE_TARGET;
+ break;
+
+ case STATE_ACQUIRE_TARGET: {
+ // Here to scope tempLaunchAction
+ int *tempLaunchAction = NULL;
+
+ int errCod = 0;
+
+ _acquireTarget++;
+
+ if (!retNodeFlag) {
+ tempLaunchAction = acquireTarget(targetX, targetY, myTree, errCod);
+ } else {
+ warning("NOT acquiring target!!!!!!!");
+ _acquireTarget = 101;
+ }
+
+ if (tempLaunchAction != NULL) {
+ if (launchAction != NULL) {
+ delete launchAction;
+ launchAction = NULL;
+ }
+
+ launchAction = tempLaunchAction;
+ }
+
+ // If no hubs are available for launching...turn must be skipped
+ if (launchAction != NULL) {
+ if (launchAction[LAUNCH_SOURCE_HUB] == 0) {
+ launchAction[LAUNCH_UNIT] = SKIP_TURN;
+ }
+ }
+
+ if ((tempLaunchAction != NULL) || (errCod == 1) || (_acquireTarget > 100)) {
+ if (tempLaunchAction == NULL) {
+ warning("\nABORTING acquire target!!!!!");
+ }
+
+ assert(launchAction != NULL);
+ delete myTree;
+ myTree = NULL;
+ _aiState = STATE_LAUNCH;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (_aiState == STATE_LAUNCH) {
+ static float randomAttenuation = 1;
+
+ if (((launchAction[LAUNCH_UNIT] == ITEM_REPAIR) || (launchAction[LAUNCH_UNIT] == ITEM_ANTIAIR) || (launchAction[LAUNCH_UNIT] == ITEM_BRIDGE) || (launchAction[LAUNCH_UNIT] == ITEM_TOWER) || (launchAction[LAUNCH_UNIT] == ITEM_RECLAIMER) || (launchAction[LAUNCH_UNIT] == ITEM_BALLOON) || (launchAction[LAUNCH_UNIT] == ITEM_MINE) || (launchAction[LAUNCH_UNIT] == ITEM_ENERGY) || (launchAction[LAUNCH_UNIT] == ITEM_SHIELD) || (launchAction[LAUNCH_UNIT] == ITEM_OFFENSE) || (launchAction[LAUNCH_UNIT] == ITEM_HUB)) && (getBuildingType(launchAction[LAUNCH_SOURCE_HUB]) == BUILDING_OFFENSIVE_LAUNCHER)) {
+ if (getPlayerEnergy() > 2) {
+ launchAction[LAUNCH_UNIT] = ITEM_GUIDED;
+ } else {
+ launchAction[LAUNCH_UNIT] = ITEM_BOMB;
+ }
+ }
+
+ if ((lastSource[currentPlayer] == launchAction[LAUNCH_SOURCE_HUB]) && (lastAngle[currentPlayer] == launchAction[LAUNCH_ANGLE]) && (lastPower[currentPlayer] == launchAction[LAUNCH_POWER])) {
+ randomAttenuation -= .2f;
+ randomAttenuation = MAX(randomAttenuation, 0.0f);
+ warning("Attenuating...");
+ } else {
+ randomAttenuation = 1;
+ }
+
+ lastSource[currentPlayer] = launchAction[LAUNCH_SOURCE_HUB];
+ lastAngle[currentPlayer] = launchAction[LAUNCH_ANGLE];
+ lastPower[currentPlayer] = launchAction[LAUNCH_POWER];
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_A, launchAction[LAUNCH_SOURCE_HUB]);
+ int energy = getPlayerEnergy();
+ warning("Computer's energy: %d", energy);
+
+ // Check if there's enough energy to launch this item
+ int n = (launchAction[1] / 6);
+ int energyRequired = (1 + n * n + n);
+
+ if (((energy - energyRequired) < 0) || (!launchAction[LAUNCH_SOURCE_HUB])) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ } else {
+ assert((launchAction[LAUNCH_UNIT] >= 0) && (launchAction[LAUNCH_UNIT] <= 18));
+
+ if ((launchAction[LAUNCH_UNIT] < 0) || (launchAction[LAUNCH_UNIT] > 18)) launchAction[LAUNCH_UNIT] = 0;
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, launchAction[LAUNCH_UNIT]);
+ }
+
+ if (launchAction[LAUNCH_UNIT] == ITEM_BOMB) {
+ if (energy > 2) {
+ if (!_vm->_rnd.getRandomNumber(4)) {
+ launchAction[LAUNCH_UNIT] = ITEM_GUIDED;
+ }
+ }
+ }
+
+ {
+ // ANGLE setting
+ int angleAdjustment = (int)(_vm->_rnd.getRandomNumber(_aiType[getCurrentPlayer()]->getAngleVariation() * AI_VAR_BASE_ANGLE) * 3.6);
+ //pos or neg choice
+ angleAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
+ angleAdjustment *= randomAttenuation;
+
+ int safeAngle = 0;
+ int lu = launchAction[LAUNCH_UNIT];
+
+ if ((lu == ITEM_ANTIAIR) || (lu == ITEM_TOWER) || (lu == ITEM_ENERGY) || (lu == ITEM_SHIELD) || (lu == ITEM_OFFENSE) || (lu == ITEM_HUB)) {
+ for (int i = 1; i < 90; i++) {
+ assert((launchAction[LAUNCH_ANGLE] < 1000) && (angleAdjustment < 360));
+
+ if (checkForAngleOverlap(launchAction[LAUNCH_SOURCE_HUB], launchAction[LAUNCH_ANGLE] + angleAdjustment)) {
+ angleAdjustment += (i % 2 ? i : -i);
+ } else {
+ safeAngle = 1;
+ i = 90;
+ }
+ }
+ } else {
+ safeAngle = 1;
+ }
+
+ if (!safeAngle) angleAdjustment = 0;
+
+ warning("Angle adjustment = %d", angleAdjustment);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, launchAction[LAUNCH_ANGLE] + angleAdjustment);
+ }
+
+ {
+ // POWER setting
+ int powerRangeFactor = (getMaxPower() - getMinPower()) / 100;
+ int powerAdjustment = static_cast<float>(_vm->_rnd.getRandomNumber(_aiType[getCurrentPlayer()]->getPowerVariation() * AI_VAR_BASE_POWER)) * powerRangeFactor;
+ //pos or neg choice
+ powerAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
+ powerAdjustment *= randomAttenuation;
+
+ warning("Power adjustment = %d", powerAdjustment);
+ int newPower = MIN(getMaxPower(), launchAction[LAUNCH_POWER] + powerAdjustment);
+ newPower = MAX(getMinPower(), launchAction[LAUNCH_POWER] + powerAdjustment);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, newPower);
+
+ assert(_vm->readVar(_vm->VAR_U32_USER_VAR_B) != -1);
+
+ if (launchAction[LAUNCH_UNIT] != SKIP_TURN) {
+ if ((launchAction[LAUNCH_SOURCE_HUB] > 0) && (launchAction[LAUNCH_SOURCE_HUB] <= 500)) {
+ if (getBuildingState(launchAction[LAUNCH_SOURCE_HUB]) != 0) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ }
+
+ if ((launchAction[LAUNCH_UNIT] == SKIP_TURN) || (launchAction[LAUNCH_POWER] == 0)) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, -1);
+ }
+ }
+
+
+ if ((launchAction[LAUNCH_SOURCE_HUB] > 0) && (launchAction[LAUNCH_SOURCE_HUB] <= 500)) {
+ int nearbyOpponents = getUnitsWithinRadius(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), 180);
+ int opponentCounter = 0;
+ int opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
+ int defenseOn = 0;
+ int defenseOff = 0;
+
+ while (opponentBuilding) {
+ if (getBuildingOwner(opponentBuilding)) {
+ if ((getBuildingType(opponentBuilding) == BUILDING_ANTI_AIR) && (getBuildingTeam(opponentBuilding) != getPlayerTeam(currentPlayer))) {
+ if (getBuildingState(opponentBuilding) == 0) {
+ defenseOn = 1;
+ } else {
+ defenseOff = 1;
+ }
+ }
+ }
+
+ opponentCounter++;
+ opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(nearbyOpponents);
+
+ if (defenseOn && defenseOff) {
+ if (!_vm->_rnd.getRandomNumber(1)) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, ITEM_TIME_EXPIRED);
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ } else {
+ if (defenseOn) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, ITEM_CLUSTER);
+ int temp = _vm->_rnd.getRandomNumber(2);
+ int tempPower = 0;
+
+ switch (temp) {
+ case 0:
+ tempPower = getMinPower();
+ break;
+
+ case 1:
+ tempPower = getMaxPower();
+ break;
+
+ default:
+ tempPower = launchAction[LAUNCH_POWER];
+ }
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, tempPower);
+ }
+ }
+ }
+
+ delete[] launchAction;
+ launchAction = NULL;
+
+ _aiState = STATE_CHOOSE_BEHAVIOR;
+
+ int rSh, rU, rP, rA = 0;
+ rSh = _vm->readVar(_vm->VAR_U32_USER_VAR_A);
+ rU = _vm->readVar(_vm->VAR_U32_USER_VAR_B);
+ rP = _vm->readVar(_vm->VAR_U32_USER_VAR_D);
+ rA = _vm->readVar(_vm->VAR_U32_USER_VAR_C);
+
+ warning("su: %d unit: %d power: %d angle: %d", rSh, rU, rP, rA);
+
+ {
+ // Checking for patterns
+ if ((_aiType[currentPlayer]->getID() != CRAWLER_CHUCKER) &&
+ (_aiType[currentPlayer]->getID() != ENERGY_HOG) && (getBuildingStackPtr() > 5))
+ _moveList[currentPlayer]->addPattern(rSh, rU, rP, rA);
+
+ int patternFound = _moveList[currentPlayer]->evaluatePattern(rSh, rU, rP, rA);
+
+ if (!_vm->_rnd.getRandomNumber(9))
+ patternFound = 0;
+
+ if (patternFound) {
+ warning("------------------------------------------>Eliminating pattern");
+
+ if (_vm->_rnd.getRandomNumber(1)) {
+ _behavior--;
+
+ if (_behavior < ENERGY_MODE)
+ _behavior = DEFENSE_MODE;
+ } else {
+ _behavior++;
+
+ if (_behavior > DEFENSE_MODE)
+ _behavior = ENERGY_MODE;
+ }
+
+ if (_behavior == ENERGY_MODE)
+ if (!getNumberOfPools())
+ _behavior = OFFENSE_MODE;
+
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
+ _aiState = STATE_CHOOSE_TARGET;
+ }
+ }
+
+ if ((rSh > 0) && (rSh < 501)) {
+ if ((rU == ITEM_ANTIAIR) || (rU == ITEM_TOWER) || (rU == ITEM_ENERGY) || (rU == ITEM_SHIELD) || (rU == ITEM_OFFENSE) || (rU == ITEM_HUB)) {
+ int tryCount = 0;
+
+ while (checkForAngleOverlap(rSh, rA) && tryCount < 25) {
+ rA = _vm->_rnd.getRandomNumber(359);
+ tryCount++;
+ }
+
+ if (tryCount < 25) {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, rA);
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+ }
+ }
+ }
+ } else {
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
+ }
+
+ // Sending behavior to SCUMM side for profiling
+ int selectedUnit = _vm->readVar(_vm->VAR_U32_USER_VAR_B);
+
+ if (selectedUnit) {
+ if (selectedUnit > 0)
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_E, _behavior);
+ else
+ _vm->writeVar(_vm->VAR_U32_USER_VAR_E, -999);
+ }
+
+ return 1;
+}
+
+int AI::chooseBehavior() {
+ static int dominantMode = 0;
+
+ if (getBuildingStackPtr() < 5)
+ return OFFENSE_MODE;
+
+ int currentPlayer = getCurrentPlayer();
+
+ int AIpersonality = _aiType[currentPlayer]->getID();
+
+ switch (AIpersonality) {
+ case BRUTAKAS:
+ dominantMode = OFFENSE_MODE;
+ break;
+
+ case AGI:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case EL_GATO:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case PIXELAHT:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case CYBALL:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case NEEP:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case WARCUPINE:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case AONE:
+ dominantMode = DEFENSE_MODE;
+ break;
+
+ case SPANDO:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case ORBNU_LUNATEK:
+ dominantMode = ENERGY_MODE;
+ break;
+
+ case CRAWLER_CHUCKER:
+ dominantMode = OFFENSE_MODE;
+ break;
+
+ case ENERGY_HOG:
+ dominantMode = ENERGY_MODE;
+ {
+ int breakFlag = 0;
+
+ for (int i = 500; i > 0; i--)
+ if ((getBuildingOwner(i) == currentPlayer) && (getBuildingType(i) == BUILDING_ENERGY_COLLECTOR))
+ breakFlag = 1;
+
+ if (!breakFlag)
+ return ENERGY_MODE;
+ }
+ break;
+
+ case RANGER:
+ dominantMode = OFFENSE_MODE;
+
+ //random chance of defense if really early in game, otherwise offense
+ if (_vm->_rnd.getRandomNumber(1) || getTurnCounter() > 4)
+ return OFFENSE_MODE;
+
+ return DEFENSE_MODE;
+ break;
+
+ default: //BRUTAKAS
+ dominantMode = OFFENSE_MODE;
+ break;
+ }
+
+ // get a list of all the visible enemy units
+ int eneCon = 0;
+ int offCon = 0;
+ int defCon = 0;
+
+ // energy mode
+ {
+ warning("Starting Energy Behavior Selection");
+ int minEnergy = 8;
+ int maxEnergy = 14;
+
+ if (dominantMode == ENERGY_MODE) {
+ eneCon = 3;
+ maxEnergy = 21;
+ } else {
+ eneCon = 5;
+ }
+
+
+ // loop through energy pool array
+ int energyPoolScummArray = getEnergyPoolsArray();
+ int numPools = getNumberOfPools();
+
+ // Prevent energy from being chosen if not enough energy to create
+ int energyAmount = getPlayerEnergy();
+
+ if ((energyAmount < 7))
+ numPools = 0;
+
+ for (int i = 1; i <= numPools; i++) {
+ int poolX = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X);
+ int poolY = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y);
+
+ int radius = energyPoolSize(i) / 2;
+ int poolMaxCount = getMaxCollectors(i);
+
+ int energyCount = 0;
+ int energyUnits = getUnitsWithinRadius(poolX, poolY, radius + 30);
+ int energyCounter = 0;
+ int energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
+
+
+ while (energyBuilding) {
+ energyCounter++;
+
+ if ((getBuildingType(energyBuilding) == BUILDING_ENERGY_COLLECTOR) && (getBuildingOwner(energyBuilding) != currentPlayer))
+ energyCount = poolMaxCount;
+
+ if ((getBuildingType(energyBuilding) == BUILDING_ENERGY_COLLECTOR) && (getBuildingOwner(energyBuilding) == currentPlayer))
+ energyCount++;
+
+ energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(energyUnits);
+
+ if (energyCount < poolMaxCount) {
+ int closestHub = getClosestUnit(poolX, poolY, 300, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ if (closestHub) {
+ eneCon = MIN(1, eneCon);
+ } else {
+ int secondClosestHub = getClosestUnit(poolX, poolY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ if (secondClosestHub)
+ eneCon = MIN(2, eneCon);
+ else
+ eneCon = MIN(3, eneCon);
+ }
+ }
+ }
+
+ int totalEnergy = estimateNextRoundEnergy(currentPlayer);
+
+ if (totalEnergy < minEnergy)
+ eneCon--;
+
+ if (totalEnergy > maxEnergy)
+ eneCon += 2;
+
+ if ((totalEnergy > 34) || (!numPools))
+ eneCon = 10;
+
+ if (dominantMode == ENERGY_MODE)
+ eneCon--;
+ }
+
+
+ // offense mode
+ {
+ warning("Starting Offense Behavior Selection");
+
+ if (dominantMode == OFFENSE_MODE) offCon = 3;
+ else offCon = 5;
+
+ int enemyArray = getEnemyUnitsVisible(currentPlayer);
+ int enemyX = 0;
+ int enemyY = 0;
+ int hubX = 0;
+ int hubY = 0;
+
+ int nearEnemyHub = 0;
+
+ // cycle through the array of buildings
+ for (int i = 0; i < 500; i++) {
+ if (int thisBuilding = _vm->_moonbase->readFromArray(enemyArray, i, 0)) {
+ enemyX = getHubX(thisBuilding);
+ enemyY = getHubY(thisBuilding);
+ int closestHub = getClosestUnit(enemyX, enemyY, 970, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int closestOL = getClosestUnit(enemyX, enemyY, 970, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int dist = 0;
+
+ if (closestOL) {
+ hubX = getHubX(closestOL);
+ hubY = getHubY(closestOL);
+ nearEnemyHub = 1;
+ }
+
+ if (closestHub) {
+ hubX = getHubX(closestHub);
+ hubY = getHubY(closestHub);
+ dist = getDistance(hubX, hubY, enemyX, enemyY);
+
+ if (dist < 480)
+ nearEnemyHub = 1;
+ }
+
+
+ if (closestHub || closestOL) {
+ int numDefenders = 0;
+ int defArray = getUnitsWithinRadius(enemyX, enemyY, 170);
+ int defCounter = 0;
+ int defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+
+ while (defenseBuilding) {
+ defCounter++;
+
+ if (((getBuildingType(defenseBuilding) == BUILDING_ANTI_AIR) ||
+ (getBuildingType(defenseBuilding) == BUILDING_SHIELD)) &&
+ (getBuildingOwner(defenseBuilding) != currentPlayer)) {
+ if (getBuildingState(defenseBuilding) == 0)
+ numDefenders++;
+ }
+
+ defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(defArray);
+
+ if (!numDefenders) {
+ int defArray2 = getUnitsWithinRadius(hubX, hubY, 170);
+ defCounter = 0;
+ int defenseBuilding2 = _vm->_moonbase->readFromArray(defArray2, 0, defCounter);
+
+ while (defenseBuilding2) {
+ defCounter++;
+
+ if (((getBuildingType(defenseBuilding2) == BUILDING_ANTI_AIR) ||
+ (getBuildingType(defenseBuilding2) == BUILDING_SHIELD)) &&
+ (getBuildingOwner(defenseBuilding2) != currentPlayer))
+ if (getBuildingState(defenseBuilding2) == 0)
+ numDefenders++;
+
+ defenseBuilding2 = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(defArray2);
+
+ }
+
+ if ((!numDefenders) && (nearEnemyHub)) {
+ if (thisBuilding > 495)
+ offCon = 1 + _vm->_rnd.getRandomNumber(1);
+ else
+ offCon = MIN(offCon, 2);
+ } else {
+ if (thisBuilding > 495) {
+ if (nearEnemyHub) {
+ offCon = MIN(offCon, 2);
+ break;
+ } else {
+ offCon = MIN(offCon, 3);
+ break;
+ }
+ } else {
+ offCon = MIN(offCon, 4);
+ }
+ }
+ }
+
+ if (getBuildingType(thisBuilding) == BUILDING_CRAWLER) {
+ if (getClosestUnit(enemyX, enemyY, 350, currentPlayer, 1, 0, 0)) {
+ int closestHub1 = getClosestUnit(enemyX, enemyY, 460, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+ int closestMine = getClosestUnit(enemyX, enemyY, 80, 0, 0, BUILDING_EXPLOSIVE_MINE, 1);
+
+ if (closestHub1 && !closestMine)
+ offCon = -1;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ _vm->_moonbase->deallocateArray(enemyArray);
+ offCon--;
+ }
+
+ // defense mode
+ {
+ warning("Starting Defense Behavior Selection");
+
+ if (dominantMode == DEFENSE_MODE)
+ defCon = 3;
+ else
+ defCon = 5;
+
+ int numDefenders = 0;
+ int openFlag = 0;
+
+ int mainHubX = getHubX(0);
+ int mainHubY = getHubY(0);
+ int mainHub = getClosestUnit(mainHubX + 10, mainHubY, 20, currentPlayer, 1, BUILDING_MAIN_BASE, 0);
+
+ int damageFlag = 0;
+
+ // cycle through the array of buildings
+ for (int i = 500; i >= 1; i--) {
+ if ((i < 497) && (defCon < 3))
+ break;
+
+ if (getBuildingOwner(i) == currentPlayer) {
+ int type = getBuildingType(i);
+ int hubX = getHubX(i);
+ int hubY = getHubY(i);
+
+ if (type == BUILDING_MAIN_BASE || type == BUILDING_ENERGY_COLLECTOR || type == BUILDING_OFFENSIVE_LAUNCHER) {
+ int nearEnemy = 0;
+ int closeBuildingsArray = getUnitsWithinRadius(hubX, hubY, 480);
+ int closeBuildingCounter = 0;
+ int closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
+
+ while (closeBuilding) {
+ closeBuildingCounter++;
+
+ if ((getBuildingOwner(closeBuilding) != currentPlayer) && (getBuildingType(closeBuilding) == BUILDING_MAIN_BASE)) {
+ nearEnemy = 1;
+ break;
+ }
+
+ closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(closeBuildingsArray);
+
+ int defCounter = 0;
+ int defArray = getUnitsWithinRadius(hubX, hubY, 170);
+ int defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ numDefenders = 0;
+
+ while (defenseBuilding) {
+ defCounter++;
+
+ if (((getBuildingType(defenseBuilding) == BUILDING_ANTI_AIR) || (getBuildingType(defenseBuilding) == BUILDING_SHIELD)) && (getBuildingOwner(defenseBuilding) == currentPlayer)) {
+ //main base has enemies near, but is defended
+ if (getBuildingState(defenseBuilding) == 0)
+ numDefenders++;
+ }
+
+ defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+ }
+
+ _vm->_moonbase->deallocateArray(defArray);
+
+ if (numDefenders > 2)
+ defCon++;
+
+ if (numDefenders < 2)
+ if (dominantMode == DEFENSE_MODE)
+ openFlag = 1;
+
+ if (!numDefenders) {
+ if (nearEnemy) {
+ if (i == mainHub) {
+ defCon = 1;
+ break;
+ } else {
+ defCon = MIN(defCon, 2);
+ }
+ } else {
+ if (i == mainHub)
+ defCon = MIN(defCon, 3);
+ else
+ defCon = MIN(defCon, 4);
+ }
+ }
+
+ if (getBuildingArmor(i) < getBuildingMaxArmor(i))
+ damageFlag = 1;
+ }
+ }
+ }
+
+ if (damageFlag && (defCon > 1))
+ defCon--;
+
+ if (!openFlag && defCon == 3)
+ defCon += 2;
+ }
+
+ warning("%s-------------------------------> Energy: %d Offense: %d Defense: %d", _aiType[currentPlayer]->getNameString(), eneCon, offCon, defCon);
+
+ if (dominantMode == DEFENSE_MODE)
+ if ((defCon <= offCon) && (defCon <= eneCon))
+ return DEFENSE_MODE;
+
+ if (dominantMode == OFFENSE_MODE)
+ if ((offCon <= eneCon) && (offCon <= defCon))
+ return OFFENSE_MODE;
+
+ if (dominantMode == ENERGY_MODE)
+ if ((eneCon <= offCon) && (eneCon <= defCon))
+ return ENERGY_MODE;
+
+ if ((defCon <= offCon) && (defCon <= eneCon))
+ return DEFENSE_MODE;
+
+ if ((offCon <= eneCon) && (offCon <= defCon))
+ return OFFENSE_MODE;
+
+ if ((eneCon <= offCon) && (eneCon <= defCon))
+ return ENERGY_MODE;
+
+ return -1;
+}
+
+int AI::chooseTarget(int behavior) {
+ int numPools = getNumberOfPools();
+ int currentPlayer = getCurrentPlayer();
+
+ int selection = 0;
+ int selectionValues[50] = {0};
+ int selectionDist = 10000000;
+
+ if (behavior == ENERGY_MODE) {
+ // loop through energy pool array
+ int energyPoolScummArray = getEnergyPoolsArray();
+
+ for (int i = 1; i <= numPools; i++) {
+ // check # units on pool
+ int numPoolSpots = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_UNITS_ON);
+
+ if (numPoolSpots == 0) {
+ // put this one in the middle
+ warning("Empty pool #%d", i);
+ selectionValues[i] = 2;
+ } else {
+ // get units w/in radius of pool
+ int poolUnitsArray = getUnitsWithinRadius(_vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X), _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y), 50);
+ int enemyPool = 0;
+ int j = 1;
+ int thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+
+ while (thisPoolUnit) {
+ if (getBuildingOwner(thisPoolUnit) != currentPlayer)
+ enemyPool = 1;
+
+ j++;
+ thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+ }
+
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+
+ // if enemy collector, put at bottom
+ if (enemyPool) {
+ selectionValues[i] = 1;
+ } else if (numPoolSpots < getMaxCollectors(i)) {
+ selectionValues[i] = 3;
+ } else {
+ // this pool is filled
+ selectionValues[i] = 0;
+ }
+ }
+
+ if (selectionValues[i] > selectionValues[selection]) {
+ selection = i;
+ } else if (selectionValues[i] == selectionValues[selection]) {
+ int poolX = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X);
+ int poolY = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y);
+
+ int closestHub = getClosestUnit(poolX, poolY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 100);
+ int thisDist = getDistance(poolX, poolY, getHubX(closestHub), getHubY(closestHub));
+
+ if (thisDist < selectionDist) {
+ selection = i;
+ selectionDist = thisDist;
+ }
+ }
+
+ }
+
+ warning("Pool selected: %d dist: %d", selection, selectionDist);
+ return selection;
+ }
+
+ if (behavior == OFFENSE_MODE) {
+ int returnBuilding = 0;
+ int attackableArray[500];
+ int nearAttackableArray[500];
+ int attackableIndex = 0;
+ int nearAttackableIndex = 0;
+
+ int enemyArray = getEnemyUnitsVisible(currentPlayer);
+
+ for (int i = 500; i >= 1; i--) {
+ int thisBuilding = _vm->_moonbase->readFromArray(enemyArray, i - 1, 0);
+
+ if (thisBuilding) {
+ if (getBuildingType(thisBuilding) == BUILDING_CRAWLER) {
+ if ((getTerrain(getHubX(thisBuilding), getHubY(thisBuilding)) != TERRAIN_TYPE_WATER) || (getPlayerEnergy() > 6)) {
+ if (getClosestUnit(getHubX(thisBuilding), getHubY(thisBuilding), 380, currentPlayer, 1, BUILDING_MAIN_BASE, 1)) {
+ returnBuilding = thisBuilding;
+ _vm->_moonbase->deallocateArray(enemyArray);
+ return returnBuilding;
+ }
+ } else {
+ continue;
+ }
+ }
+
+ int enemyX = getHubX(thisBuilding);
+ int enemyY = getHubY(thisBuilding);
+ int closestHub = getClosestUnit(enemyX, enemyY, 930, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+ int dist = getDistance(enemyX, enemyY, getHubX(closestHub), getHubY(closestHub));
+
+ if (getBuildingType(thisBuilding) != BUILDING_BALLOON) {
+ if (dist < 470) {
+ attackableArray[attackableIndex] = thisBuilding;
+ attackableIndex++;
+ } else {
+ nearAttackableArray[nearAttackableIndex] = thisBuilding;
+ nearAttackableIndex++;
+ }
+ }
+ }
+ }
+
+ _vm->_moonbase->deallocateArray(enemyArray);
+
+ if (attackableIndex) {
+ int thisWorth = 0;
+ int savedWorth = 1;
+ int closestSavedShield = 0;
+ int closestSavedAntiAir = 0;
+
+ for (int i = 0; i < attackableIndex; i++) {
+ thisWorth = getBuildingWorth(attackableArray[i]);
+
+ if (thisWorth == savedWorth) {
+ int closestShield = getClosestUnit(getHubX(attackableArray[i]), getHubY(attackableArray[i]), 180, currentPlayer, 0, BUILDING_SHIELD, 1);
+ int closestAntiAir = getClosestUnit(getHubX(attackableArray[i]), getHubY(attackableArray[i]), 180, currentPlayer, 0, BUILDING_ANTI_AIR, 1);
+
+ if (closestSavedShield > closestShield) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = attackableArray[i];
+ } else {
+ if (closestSavedAntiAir > closestAntiAir) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = attackableArray[i];
+ }
+ }
+ }
+
+ if (thisWorth > savedWorth) {
+ savedWorth = thisWorth;
+ returnBuilding = attackableArray[i];
+ }
+ }
+ } else {
+ if (nearAttackableIndex) {
+ int thisWorth = 0;
+ int savedWorth = 1;
+ int closestSavedShield = 0;
+ int closestSavedAntiAir = 0;
+
+ for (int i = 0; i < nearAttackableIndex; i++) {
+ thisWorth = getBuildingWorth(nearAttackableArray[i]);
+
+ if (thisWorth == savedWorth) {
+ int closestShield = getClosestUnit(getHubX(nearAttackableArray[i]), getHubY(nearAttackableArray[i]), 180, currentPlayer, 0, BUILDING_SHIELD, 1);
+ int closestAntiAir = getClosestUnit(getHubX(nearAttackableArray[i]), getHubY(nearAttackableArray[i]), 180, currentPlayer, 0, BUILDING_ANTI_AIR, 1);
+
+ if (closestSavedShield > closestShield) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = nearAttackableArray[i];
+ } else {
+ if (closestSavedAntiAir > closestAntiAir) {
+ savedWorth = thisWorth;
+ closestSavedShield = closestShield;
+ closestSavedAntiAir = closestAntiAir;
+ returnBuilding = nearAttackableArray[i];
+ }
+ }
+ }
+
+ if (thisWorth > savedWorth) {
+ savedWorth = thisWorth;
+ returnBuilding = nearAttackableArray[i];
+ }
+ }
+ }
+ }
+
+ if (!returnBuilding) {
+ for (int i = 500; i > 496; i--) {
+ if (getBuildingOwner(i)) {
+ if (getBuildingTeam(i) != getPlayerTeam(currentPlayer)) {
+ returnBuilding = i;
+ i = 0;
+ }
+ }
+ }
+ }
+
+ warning("Attack target: %d", returnBuilding);
+
+ assert(returnBuilding);
+ return returnBuilding;
+ }
+
+ if (behavior == DEFENSE_MODE) {
+ int returnBuilding = 0;
+
+ int savedTally = 0;
+ int savedDamage;
+ float savedNumDefenses = 0;
+ int savedWorth = 0;
+
+ float numDefenses = 0;
+ int tally = 0;
+ int attackable = 0;
+ int attacked = 0;
+ int damage = 0;
+
+ int type = 0;
+ int worth = 0;
+
+
+ int attackedX = 0;
+ int attackedY = 0;
+ int attackedUnit = 0;
+
+ if (getLastAttacked(attackedX, attackedY)) {
+ (void)getClosestUnit(attackedX + 10, attackedY, 50, currentPlayer, 1, 0, 0); // Unused?
+ }
+
+ // loop through own units
+ for (int i = 1; i <= 500; i++) {
+ numDefenses = 0;
+ attackable = 0;
+ attacked = 0;
+ damage = 0;
+ type = 0;
+ worth = 0;
+
+ int owner = getBuildingOwner(i);
+
+ if (owner == currentPlayer) {
+ type = getBuildingType(i);
+
+ // if current unit in [hub, offense, energy, tower]
+ if ((type == BUILDING_MAIN_BASE) || (type == BUILDING_ENERGY_COLLECTOR) || (type == BUILDING_OFFENSIVE_LAUNCHER) || (type == BUILDING_TOWER)) {
+ worth = getBuildingWorth(i);
+
+ // Calculate current defenses
+ int x = getHubX(i);
+ int y = getHubY(i);
+ assert(x >= 0);
+ assert(y >= 0);
+
+ int defenseArray = getUnitsWithinRadius(x, y, 180);
+ int j = 0;
+ // cycle through the defense units close to the target building
+ int defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
+
+ // loop on all defenses w/in 180
+ while (defenseBuilding != 0) {
+ int defenseType = getBuildingType(defenseBuilding);
+
+ // sub for each
+ if ((defenseType == BUILDING_ANTI_AIR) || (defenseType == BUILDING_SHIELD)) {
+ if (getBuildingState(defenseBuilding) == 0)
+ numDefenses += 1;
+ else
+ numDefenses += .5;
+ }
+
+ j++;
+ defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
+ }
+
+ _vm->_moonbase->deallocateArray(defenseArray);
+
+ // Calculate if this unit is attackable
+ // get dist to nearest enemy hub, offense
+ int closestHub = getClosestUnit(x, y, getMaxX(), getCurrentPlayer(), 0, BUILDING_MAIN_BASE, 0);
+ int numStridesToHub = getDistance(getHubX(closestHub), getHubY(closestHub), x, y) / 480;
+ closestHub = getClosestUnit(x, y, getMaxX(), getCurrentPlayer(), 0, BUILDING_OFFENSIVE_LAUNCHER, 0);
+ int numStridesToOL = getDistance(getHubX(closestHub), getHubY(closestHub), x, y) / 800;
+
+ // sub for each stride away
+ if (!numStridesToOL || !numStridesToHub)
+ attackable = 1;
+
+ // Check if this unit was just attacked
+ if (attackedUnit == i)
+ attacked = 1;
+
+ if (!numDefenses) {
+ tally = 1;
+
+ if (attackable) {
+ tally = 4;
+
+ if (attacked) {
+ tally = 5;
+ }
+ }
+ } else {
+ if (attackable) {
+ tally = 2;
+
+ if (attacked) {
+ tally = 3;
+ }
+ }
+ }
+
+ // Check if this unit is damaged
+ int saveFlag = 0;
+
+ if (tally > savedTally) {
+ saveFlag = 1;
+ } else {
+ if (tally == savedTally) {
+ if (worth > savedWorth) {
+ saveFlag = 1;
+
+ if (numDefenses > savedNumDefenses) {
+ saveFlag = 0;
+ }
+ }
+
+ if (damage > savedDamage) {
+ saveFlag = 1;
+
+ if (numDefenses > savedNumDefenses) {
+ saveFlag = 0;
+ }
+ }
+
+ if (numDefenses < savedNumDefenses) {
+ saveFlag = 1;
+ }
+
+ if (numDefenses >= 3) {
+ saveFlag = 0;
+ }
+ }
+ }
+
+ if (saveFlag) {
+ savedTally = tally;
+ savedWorth = worth;
+ savedDamage = damage;
+ savedNumDefenses = numDefenses;
+ returnBuilding = i;
+ }
+ }
+ }
+ }
+
+ return returnBuilding;
+ }
+
+ return 0;
+}
+
+Tree *AI::initApproachTarget(int targetX, int targetY, Node **retNode) {
+ int sourceHub = 0;
+
+ if (_behavior == 2)
+ sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
+ else
+ sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
+
+ Traveller *myTraveller = new Traveller(getHubX(sourceHub), getHubY(sourceHub), this);
+ myTraveller->setSourceHub(sourceHub);
+
+ //target adjustment so that room is allowed for the appropriate shot
+ int tempAngle = calcAngle(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+ int adjX = -120 * cos(degToRad(tempAngle));
+ int adjY = -120 * sin(degToRad(tempAngle));
+
+ Traveller::setTargetPosX(targetX + adjX);
+ Traveller::setTargetPosY(targetY + adjY);
+ Traveller::setMaxDist(340);
+
+ Tree *myTree = new Tree(myTraveller, TREE_DEPTH, this);
+ *retNode = myTree->aStarSearch_singlePassInit();
+
+ return myTree;
+}
+
+int *AI::approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode) {
+ int *retVal = NULL;
+
+ *currentNode = NULL;
+ Node *retNode = myTree->aStarSearch_singlePass();
+
+ if (*currentNode != NULL)
+ warning("########################################### Got a possible solution");
+
+ if (myTree->IsBaseNode(retNode)) {
+ warning("########################################### Returning Base Node");
+ retVal = new int[4];
+ retVal[0] = -1;
+ return retVal;
+ }
+
+ if (retNode == NULL) {
+ return retVal;
+ } else {
+ retVal = new int[4];
+
+ Traveller *retTraveller = reinterpret_cast<Traveller *>(retNode->getFirstStep()->getContainedObject());
+
+ // set launching hub, item to launch, angle of launch, power of launch
+ // if water flag is set, launch bridge instead of hub
+ retVal[0] = static_cast<Traveller *>(myTree->getBaseNode()->getContainedObject())->getSourceHub();
+
+ if (retTraveller->getWaterFlag()) {
+ int powAngle = getPowerAngleFromPoint(retTraveller->getWaterSourceX(),
+ retTraveller->getWaterSourceY(),
+ retTraveller->getWaterDestX(),
+ retTraveller->getWaterDestY(),
+ 15);
+
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ retVal[0] = getClosestUnit(retTraveller->getWaterSourceX() + 10, retTraveller->getWaterSourceY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+
+ retVal[1] = ITEM_BRIDGE;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ warning("Target Bridge Coords: <%d, %d> ", retTraveller->getWaterDestX(), retTraveller->getWaterDestY());
+ } else {
+ retVal[1] = ITEM_HUB;
+ retVal[2] = retTraveller->getAngleTo();
+ retVal[3] = retTraveller->getPowerTo();
+ }
+
+
+ int whoseTurn = getCurrentPlayer();
+
+ if ((_lastXCoord[whoseTurn]).size() >= MAX_MEMORY) {
+ (_lastXCoord[whoseTurn]).erase((_lastXCoord[whoseTurn]).begin());
+ (_lastYCoord[whoseTurn]).erase((_lastYCoord[whoseTurn]).begin());
+ }
+
+ (_lastXCoord[whoseTurn]).push_back(retTraveller->getPosX());
+ (_lastYCoord[whoseTurn]).push_back(retTraveller->getPosY());
+
+ int temp = static_cast<int>(retTraveller->calcT());
+ int temp2 = static_cast<int>(retTraveller->getValueG());
+ int x = static_cast<int>(retTraveller->getPosX());
+ int y = static_cast<int>(retTraveller->getPosY());
+ warning("Target Coords: <%d, %d> G-value: %d T-value: %d", x, y, temp2, temp);
+ xTarget = x;
+ yTarget = y;
+ }
+
+ return retVal;
+}
+
+Tree *AI::initAcquireTarget(int targetX, int targetY, Node **retNode) {
+ int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
+ warning("My coords (%d): %d %d", sourceHub, getHubX(sourceHub), getHubY(sourceHub));
+
+ Sortie::setSourcePos(getHubX(sourceHub), getHubY(sourceHub));
+ Sortie::setTargetPos(targetX, targetY);
+ Sortie *myBaseTarget = new Sortie(this);
+ myBaseTarget->setValueG(0);
+
+ myBaseTarget->setUnitType(ITEM_BOMB);
+ myBaseTarget->setShotPos(-1, -1);
+
+ int unitsArray = getUnitsWithinRadius(targetX + 7, targetY, 211);
+
+ warning("Target Coords: <%d, %d> Source Coords: <%d, %d>", targetX, targetY, getHubX(sourceHub) , getHubY(sourceHub));
+
+ myBaseTarget->setEnemyDefenses(unitsArray, targetX, targetY);
+
+ int thisElement = _vm->_moonbase->readFromArray(unitsArray, 0, 0);
+
+ _vm->_moonbase->deallocateArray(unitsArray);
+
+ if (!thisElement) {
+ delete myBaseTarget;
+ return NULL;
+ }
+
+ Tree *myTree = new Tree(myBaseTarget, 4, this);
+ *retNode = myTree->aStarSearch_singlePassInit();
+
+ return myTree;
+}
+
+int *AI::acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode) {
+ int currentPlayer = getCurrentPlayer();
+ int *retVal = NULL;
+
+ Node *retNode = myTree->aStarSearch_singlePass();
+
+ if (myTree->IsBaseNode(retNode))
+ return acquireTarget(targetX, targetY);
+
+ if (retNode == NULL) {
+ errorCode = 0;
+ return retVal;
+ }
+
+ Sortie *thisSortie = static_cast<Sortie *>(retNode->getFirstStep()->getContainedObject());
+ int unitToShoot = thisSortie->getUnitType();
+
+ if (unitToShoot < 0) {
+ errorCode = 1;
+ return retVal;
+ }
+
+ if (unitToShoot == ITEM_CRAWLER) {
+ warning("target acquisition is launching a crawler");
+ }
+
+ int shotTargetX = thisSortie->getShotPosX();
+ int shotTargetY = thisSortie->getShotPosY();
+ int theTarget = getClosestUnit(shotTargetX + 5, shotTargetY, getMaxX(), 0, 0, 0, 0, 0);
+
+
+ int sourceOL = 0;
+ int sourceX = thisSortie->getSourcePosX();
+ int sourceY = thisSortie->getSourcePosY();
+
+ int sourceHub = getClosestUnit(sourceX + 5, sourceY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+
+ sourceOL = getClosestUnit(sourceX, sourceY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1, 110);
+
+ if (sourceOL) {
+ sourceHub = sourceOL;
+ sourceX = getHubX(sourceOL);
+ sourceY = getHubY(sourceOL);
+ }
+
+ if (!sourceHub) sourceHub = getClosestUnit(sourceX + 5, sourceY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+
+ int powAngle = getPowerAngleFromPoint(sourceX, sourceY, shotTargetX, shotTargetY, 15, sourceOL);
+ warning("The source (%d: <%d, %d>) The target (%d: <%d, %d>)", sourceHub, sourceX, sourceY, theTarget, shotTargetX, shotTargetY);
+
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ retVal = new int[4];
+
+ retVal[0] = sourceHub;
+ retVal[1] = unitToShoot;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ warning("Unit to shoot: %d", unitToShoot);
+
+ return retVal;
+}
+
+int *AI::acquireTarget(int targetX, int targetY) {
+ int *retVal = new int[4];
+ int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+
+ if (!sourceHub)
+ sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+
+ int directAngle = calcAngle(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+ int directDistance = getDistance(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+
+ retVal[0] = sourceHub;
+ retVal[1] = ITEM_OFFENSE;
+ retVal[2] = directAngle;
+ retVal[3] = MAX(MIN(getMaxPower() * directDistance / 500, getMaxPower()), getMinPower());
+
+ return retVal;
+}
+
+int *AI::energizeTarget(int &targetX, int &targetY, int index) {
+ int n = 10;
+ static int currentPlayer = 0;
+ static int pool = 0;
+ static int radius = 0;
+ static int poolUnitsArray = 0;
+ static int j = 0;
+ static int k = 0;
+ static int sameUnit = 0;
+ static int nextUnit = 0;
+ static int attempt = 0;
+
+ if (!index) {
+ warning("index is 0!");
+ currentPlayer = getCurrentPlayer();
+ pool = 0;
+
+ // get the pool that's closest to the target coords
+ for (int i = 1; i <= getNumberOfPools(); i++) {
+ int poolX = _vm->_moonbase->readFromArray(getEnergyPoolsArray(), i, ENERGY_POOL_X);
+ int poolY = _vm->_moonbase->readFromArray(getEnergyPoolsArray(), i, ENERGY_POOL_Y);
+
+ if ((poolX == targetX) && (poolY == targetY)) {
+ pool = i;
+ }
+ }
+
+ // calculate the appropriate radius
+ radius = energyPoolSize(pool) / 2;
+
+ // create test points
+ k = 0;
+ j = 0;
+ nextUnit = 0;
+ sameUnit = 0;
+ attempt = 0;
+ }
+
+ if (poolUnitsArray)
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+
+ poolUnitsArray = getUnitsWithinRadius(targetX, targetY, 450);
+ assert(poolUnitsArray);
+
+ // 0 is for energy collectors, 1 is for circumnavigating hubs
+ if (k < 2) {
+ if (!sameUnit) {
+ sameUnit = 1;
+ attempt = 0;
+ nextUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+ j++;
+ }
+
+ if (nextUnit) {
+ if ((getBuildingType(nextUnit) == BUILDING_MAIN_BASE) && (getBuildingOwner(nextUnit) == currentPlayer)) {
+ int minAngle = 0;
+ int hubToPoolAngle = 0;
+ int testAngle = 0;
+ int testDist = 0;
+ static int xPos = 0;
+ static int yPos = 0;
+ static int newAttempt = 1;
+
+ if (sameUnit) {
+ if (k == 0) {
+ int poolToHubAngle = calcAngle(targetX, targetY, getHubX(nextUnit), getHubY(nextUnit));
+ minAngle = poolToHubAngle - 45;
+ } else {
+ hubToPoolAngle = calcAngle(getHubX(nextUnit), getHubY(nextUnit), targetX, targetY);
+ }
+ }
+
+ if (attempt < n) {
+ static int power = 0;
+ static int angle = 0;
+
+ if (newAttempt) {
+ newAttempt = 0;
+
+ if (k == 0) {
+ testAngle = (_vm->_rnd.getRandomNumber(89) + minAngle) % 360;
+ testDist = radius;
+
+ xPos = targetX + testDist * cos(degToRad(testAngle));
+ yPos = targetY + testDist * sin(degToRad(testAngle));
+ } else {
+ switch (_vm->_rnd.getRandomNumber(1)) {
+ case 0:
+ testAngle = (hubToPoolAngle + (45 + _vm->_rnd.getRandomNumber(19))) % 360;
+ break;
+
+ default:
+ testAngle = (hubToPoolAngle + (315 - _vm->_rnd.getRandomNumber(19))) % 360;
+ break;
+ }
+
+ testDist = (((((double)n - (double)attempt) / n) * .5) + .5) * (getDistance(getHubX(nextUnit), getHubY(nextUnit), targetX, targetY) / .8);
+ xPos = getHubX(nextUnit) + testDist * cos(degToRad(testAngle));
+ yPos = getHubY(nextUnit) + testDist * sin(degToRad(testAngle));
+ }
+
+ // check if points are good
+ int powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), xPos, yPos, 15);
+ powAngle = abs(powAngle);
+
+ power = powAngle / 360;
+ angle = powAngle - (power * 360);
+ }
+
+ int result = 0;
+ result = simulateBuildingLaunch(getHubX(nextUnit), getHubY(nextUnit), power, angle, 10, 1);
+
+ if (result) {
+ newAttempt = 1;
+
+ if (result > 0) {
+ xPos = (xPos + getMaxX()) % getMaxX();
+ yPos = (yPos + getMaxY()) % getMaxY();
+
+ result = 1;
+ } else {
+ // Drop a bridge for the cord
+ int yCoord = -result / getMaxX();
+ int xCoord = -result - (yCoord * getMaxX());
+
+ if (checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = getTerrainSquareSize();
+ xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+ yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+ int xDist = xCoord - xPos;
+ int yDist = yCoord - yPos;
+ xPos = xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)));
+ yPos = yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)));
+
+ nextUnit = getClosestUnit(xPos, yPos, 480, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+ int powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), xPos, yPos, 15);
+
+ powAngle = abs(powAngle);
+ power = powAngle / 360;
+ angle = powAngle - (power * 360);
+
+ int *retVal = new int[4];
+
+ retVal[0] = nextUnit;
+ retVal[1] = ITEM_BRIDGE;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ if (nextUnit <= 0)
+ retVal[0] = 0;
+
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+ return retVal;
+ }
+ }
+
+ if (result > 0) {
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+
+ targetX = xPos;
+ targetY = yPos;
+
+ int *retVal = new int[4];
+
+ retVal[0] = nextUnit;
+
+ if (k == 0) {
+ retVal[1] = ITEM_ENERGY;
+ } else {
+ retVal[1] = ITEM_HUB;
+ }
+
+ retVal[2] = angle;
+ retVal[3] = power;
+ return retVal;
+ }
+ } else {
+ int *retVal = new int[4];
+ retVal[0] = 0;
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+
+ return retVal;
+ }
+
+ attempt++;
+ } else {
+ sameUnit = 0;
+ }
+ } else {
+ sameUnit = 0;
+ }
+ } else {
+ sameUnit = 0;
+ k++;
+ j = 0;
+ }
+ } else {
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+ return NULL;
+ }
+
+ _vm->_moonbase->deallocateArray(poolUnitsArray);
+ poolUnitsArray = 0;
+ int *retVal = new int[4];
+ retVal[0] = 0;
+
+ return retVal;
+}
+
+int *AI::offendTarget(int &targetX, int &targetY, int index) {
+ int *retVal = NULL;
+
+ int target = getClosestUnit(targetX + 10, targetY, 20, 0, 0, 0, 0);
+
+ if (!target)
+ target = getClosestUnit(targetX + 10, targetY, 0, 0, 0, 0, 0);
+
+ warning("The target inside the offendTarget routine is: %d", target);
+ int type = getBuildingType(target);
+ int unit = 0;
+
+ DefenseUnit *thisUnit;
+
+ switch (type) {
+ case BUILDING_OFFENSIVE_LAUNCHER:
+ thisUnit = new OffenseUnit(this);
+ break;
+
+ case BUILDING_TOWER:
+ thisUnit = new TowerUnit(this);
+ break;
+
+ case BUILDING_MAIN_BASE:
+ thisUnit = new HubUnit(this);
+ break;
+
+ case BUILDING_ENERGY_COLLECTOR:
+ thisUnit = new EnergyUnit(this);
+ break;
+
+ case BUILDING_CRAWLER:
+ thisUnit = new CrawlerUnit(this);
+ break;
+
+ case BUILDING_BRIDGE:
+ thisUnit = new BridgeUnit(this);
+ break;
+
+ case BUILDING_SHIELD:
+ thisUnit = new ShieldUnit(this);
+ break;
+
+ default:
+ thisUnit = new HubUnit(this);
+ break;
+ }
+
+ thisUnit->setPos(targetX, targetY);
+ thisUnit->setID(target);
+
+ int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+ int sourceOL = 0;
+ sourceOL = getClosestUnit(targetX, targetY, 900, getCurrentPlayer(), 1, BUILDING_OFFENSIVE_LAUNCHER, 1, 110);
+
+ unit = thisUnit->selectWeapon(_vm->_rnd.getRandomNumber(4));
+
+ if (sourceOL) {
+ if ((unit == ITEM_BOMB) || (unit == ITEM_CLUSTER) || (unit == ITEM_GUIDED) || (unit == ITEM_EMP) || (unit == ITEM_SPIKE) || (unit == ITEM_CRAWLER) || (unit == ITEM_VIRUS)) {
+ sourceHub = sourceOL;
+ }
+ }
+
+ if (!sourceHub) {
+ retVal = new int[4];
+
+ retVal[1] = SKIP_TURN;
+ return retVal;
+ }
+
+
+ if ((thisUnit->getType() == BUILDING_CRAWLER) && (unit == SKIP_TURN)) {
+ retVal = new int[4];
+ retVal[1] = unit;
+ delete thisUnit;
+ return retVal;
+ }
+
+ if (unit == ITEM_CRAWLER) {
+ warning("******** offense is launching a crawler ********");
+ warning("The defensive unit is: %d", unit);
+ }
+
+ Common::Point *targetCoords;
+ int dist = getDistance(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+ targetCoords = thisUnit->createTargetPos(0, dist, unit, getHubX(sourceHub), getHubY(sourceHub));
+
+ int powAngle = getPowerAngleFromPoint(getHubX(sourceHub), getHubY(sourceHub), targetCoords->x, targetCoords->y, 15, sourceOL);
+ powAngle = abs(powAngle);
+ int power = powAngle / 360;
+ int angle = powAngle % 360;
+
+ if (unit == ITEM_MINE)
+ power -= 30;
+
+ targetX = targetCoords->x;
+ targetY = targetCoords->y;
+
+ if (targetX < 0)
+ targetX = (targetX + getMaxX()) % getMaxX();
+
+ if (targetY < 0)
+ targetY = (targetY + getMaxY()) % getMaxY();
+
+ assert(targetX >= 0 && targetY >= 0);
+ delete targetCoords;
+ delete thisUnit;
+
+ retVal = new int[4];
+
+ retVal[0] = sourceHub;
+ retVal[1] = unit;
+ retVal[2] = angle;
+ retVal[3] = power;
+
+ return retVal;
+}
+
+int *AI::defendTarget(int &targetX, int &targetY, int index) {
+ int *retVal = NULL;
+ Defender *thisDefender = new Defender(this);
+ int defStatus = thisDefender->calculateDefenseUnitPosition(targetX, targetY, index);
+
+ if (defStatus > 0) {
+ targetX = thisDefender->getTargetX();
+ targetY = thisDefender->getTargetY();
+ retVal = new int[4];
+
+ retVal[0] = thisDefender->getSourceUnit();
+ retVal[1] = thisDefender->getUnit();
+ retVal[2] = thisDefender->getAngle();
+ retVal[3] = thisDefender->getPower();
+ }
+
+ if (defStatus == 0) {
+ retVal = new int[4];
+ retVal[0] = 0;
+ }
+
+ if (defStatus == -1) {
+ if (thisDefender->getTargetX() || thisDefender->getTargetY()) {
+ targetX = thisDefender->getTargetX();
+ targetY = thisDefender->getTargetY();
+ }
+
+ retVal = new int[4];
+ retVal[0] = thisDefender->getSourceUnit();
+ retVal[1] = thisDefender->getUnit();
+ retVal[2] = thisDefender->getAngle();
+ retVal[3] = thisDefender->getPower();
+ }
+
+ if (defStatus == -3) {
+ retVal = new int[4];
+ retVal[0] = 0;
+ retVal[1] = SKIP_TURN;
+ retVal[2] = 0;
+ retVal[3] = 0;
+ }
+
+ assert(targetX >= 0 && targetY >= 0);
+
+ if (retVal[1] == ITEM_CRAWLER) {
+ warning("defend target is launching a crawler");
+ }
+
+ delete thisDefender;
+ return retVal;
+}
+
+int AI::getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled) {
+ assert((unitType >= 0) && (unitType <= 12));
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_CLOSEST_UNIT], 7, x, y, radius, player, alignment, unitType, checkUnitEnabled);
+ return retVal;
+}
+
+int AI::getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist) {
+ assert((unitType >= 0) && (unitType <= 12));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_CLOSEST_UNIT], 8, x, y, radius, player, alignment, unitType, checkUnitEnabled, minDist);
+ return retVal;
+}
+
+int AI::getDistance(int originX, int originY, int endX, int endY) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_DIST], 4, originX, originY, endX, endY);
+ return retVal;
+}
+
+int AI::calcAngle(int originX, int originY, int endX, int endY) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, 0);
+ return retVal;
+}
+
+int AI::calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, noWrapFlag);
+ return retVal;
+}
+
+int AI::getTerrain(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_TERRAIN_TYPE], 2, x, y);
+ return retVal;
+}
+
+int AI::estimateNextRoundEnergy(int player) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_ESTIMATE_NEXT_ROUND_ENERGY], 1, player);
+ return retVal / 10;
+}
+
+int AI::getHubX(int hub) {
+ assert(hub >= 0 && hub <= 500);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_HUB_X, hub);
+ return retVal;
+}
+
+int AI::getHubY(int hub) {
+ assert(hub >= 0 && hub <= 500);
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_HUB_Y, hub);
+ return retVal;
+}
+
+int AI::getMaxX() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WORLD_X_SIZE);
+ return retVal;
+}
+
+int AI::getMaxY() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WORLD_Y_SIZE);
+ return retVal;
+}
+
+int AI::getCurrentPlayer() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_CURRENT_PLAYER);
+ assert(retVal != 0);
+ return retVal;
+}
+
+int AI::getMaxPower() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_MAX_POWER);
+ return retVal;
+}
+
+int AI::getMinPower() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_MIN_POWER);
+ return retVal;
+}
+
+int AI::getTerrainSquareSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TERRAIN_SQUARE_SIZE);
+ return retVal;
+}
+
+int AI::getBuildingOwner(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_OWNER, building);
+ return retVal;
+}
+
+int AI::getBuildingState(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_STATE, building);
+ return retVal;
+}
+
+int AI::getBuildingType(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TYPE, building);
+ return retVal;
+}
+
+int AI::getBuildingArmor(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_ARMOR, building);
+ return retVal;
+}
+
+int AI::getBuildingWorth(int building) {
+ assert((building > 0) && (building < 501));
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_WORTH, building);
+ return retVal;
+}
+
+int AI::getEnergyPoolsArray() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_ENERGY_POOLS_ARRAY);
+ return retVal;
+}
+
+int AI::getCoordinateVisibility(int x, int y, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 4, D_GET_COORDINATE_VISIBILITY, x, y, playerNum);
+ return retVal;
+}
+
+int AI::getUnitVisibility(int unit, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 3, D_GET_UNIT_VISIBILITY, unit, playerNum);
+ return retVal;
+}
+
+int AI::getEnergyPoolVisibility(int pool, int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 3, D_GET_ENERGY_POOL_VISIBILITY, pool, playerNum);
+ return retVal;
+}
+
+int AI::getNumberOfPools() {
+ int retVal = 0;
+
+ if (_aiType[getCurrentPlayer()]->getID() == ENERGY_HOG) {
+ retVal = 1;
+ } else {
+ retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_POOLS);
+ }
+
+ return retVal;
+}
+
+int AI::getNumberOfPlayers() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_PLAYERS);
+ return retVal;
+}
+
+int AI::getPlayerEnergy() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_ENERGY);
+ return static_cast<int>(static_cast<float>(retVal) / 10.0);
+}
+
+int AI::getPlayerMaxTime() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_MAX_TIME);
+ return retVal;
+}
+
+int AI::getWindXSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED);
+ return retVal;
+}
+
+int AI::getWindYSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED);
+ return retVal;
+}
+
+int AI::getTotalWindSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TOTAL_WIND_SPEED);
+ return retVal;
+}
+
+int AI::getWindXSpeedMax() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED_MAX);
+ return retVal;
+}
+
+int AI::getWindYSpeedMax() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED_MAX);
+ return retVal;
+}
+
+int AI::getBigXSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BIG_X_SIZE);
+ return retVal;
+}
+
+int AI::getBigYSize() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BIG_Y_SIZE);
+ return retVal;
+}
+
+int AI::getEnergyPoolWidth(int pool) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_ENERGY_POOL_WIDTH, pool);
+ return retVal;
+}
+
+int AI::getBuildingMaxArmor(int building) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_MAX_ARMOR, building);
+ return retVal;
+}
+
+int AI::getTimerValue(int timerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_TIMER_VALUE, timerNum);
+ return retVal;
+}
+
+int AI::getLastAttacked(int &x, int &y) {
+ int currentPlayer = getCurrentPlayer();
+ x = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_X, currentPlayer);
+ y = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_Y, currentPlayer);
+
+ if (x || y) return 1;
+
+ return 0;
+}
+
+int AI::getPlayerTeam(int player) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_PLAYER_TEAM, player);
+ return retVal;
+}
+
+int AI::getBuildingTeam(int building) {
+ assert((building >= 1) && (building <= 500));
+
+ if (getBuildingOwner(building) == 0) return 0;
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TEAM, building);
+ return retVal;
+}
+
+int AI::getFOW() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_FOW);
+ return retVal;
+}
+
+int AI::getAnimSpeed() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_ANIM_SPEED);
+ return retVal;
+}
+
+int AI::getBuildingStackPtr() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_BUILDING_STACK_PTR);
+ return retVal;
+}
+
+int AI::getTurnCounter() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_SCUMM_DATA], 1, D_GET_TURN_COUNTER);
+ return retVal;
+}
+
+int AI::getGroundAltitude(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_GROUND_ALTITUDE], 2, x, y);
+ return retVal;
+}
+
+int AI::checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_CORD_OVERLAP], 4, xStart, yStart, affectRadius, simulateFlag);
+ return retVal;
+}
+
+int AI::checkForAngleOverlap(int unit, int angle) {
+ assert(angle > -721);
+ assert(angle < 721);
+
+ if (!unit) return 0;
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_ANGLE_OVERLAP], 2, unit, angle);
+ return retVal;
+}
+
+int AI::checkForUnitOverlap(int x, int y, int radius, int ignoredUnit) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_UNIT_OVERLAP], 4, x, y, radius, ignoredUnit);
+ return retVal;
+}
+
+int AI::checkForEnergySquare(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_FOR_ENERGY_SQUARE], 2, x, y);
+ return retVal;
+}
+
+int AI::aiChat() {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_AI_CHAT], 0);
+ return retVal;
+}
+
+int AI::getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_POWER_ANGLE_FROM_POINT], 6, originX, originY, endX, endY, threshold, olFlag);
+ return retVal;
+}
+
+int AI::getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_POWER_ANGLE_FROM_POINT], 5, originX, originY, endX, endY, threshold);
+ return retVal;
+}
+
+int AI::checkIfWaterState(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_IF_WATER_STATE], 2, x, y);
+ return retVal;
+}
+
+int AI::checkIfWaterSquare(int x, int y) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_CHECK_IF_WATER_SQUARE], 2, x, y);
+ return retVal;
+}
+
+int AI::getUnitsWithinRadius(int x, int y, int radius) {
+ assert(x >= 0);
+ assert(y >= 0);
+ assert(radius >= 0);
+
+ debug(0, "getUnitsWithinRadius(%d, %d, %d)", x, y, radius);
+
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_UNITS_WITHIN_RADIUS], 3, x, y, radius);
+ return retVal;
+}
+
+int AI::getLandingPoint(int x, int y, int power, int angle) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_LANDING_POINT], 4, x, y, power, angle);
+ return retVal;
+}
+
+int AI::getEnemyUnitsVisible(int playerNum) {
+ int retVal = _vm->_moonbase->callScummFunction(_mcpParams[F_GET_ENEMY_UNITS_VISIBLE], 1, playerNum);
+ return retVal;
+}
+
+float AI::degToRad(float degrees) {
+ return degrees * M_PI / 180.;
+}
+
+void AI::limitLocation(int &a, int &b, int c, int d) {
+ if (a >= 0) {
+ a = (a % c);
+ } else {
+ a = (c - (abs(a) % c));
+ }
+
+ if (b >= 0) {
+ b = (b % d);
+ } else {
+ b = (d - (abs(b) % d));
+ }
+}
+
+int AI::energyPoolSize(int pool) {
+ int width = getEnergyPoolWidth(pool);
+
+ switch (width) {
+ case 126:
+ return 115;
+
+ case 116:
+ return 100;
+
+ case 63:
+ return 60;
+ }
+
+ return 0;
+}
+
+int AI::getMaxCollectors(int pool) {
+ int width = getEnergyPoolWidth(pool);
+
+ switch (width) {
+ case 126:
+ return 4;
+
+ case 116:
+ return 3;
+
+ case 63:
+ return 2;
+ }
+
+ return 0;
+}
+
+int AI::simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy) {
+ static int sXSpeed = 0;
+ static int sYSpeed = 0;
+ static int sZSpeed = 0;
+ static int sXLoc = 0;
+ static int sYLoc = 0;
+ static int sZLoc = 0;
+ static int sFrictionCount = 0;
+ static int sWhichRadius = 0;
+ static int sWhichUnit = 0;
+
+ int gWindXSpeed = getWindXSpeed();
+ int gWindYSpeed = getWindYSpeed();
+ int gTotalWindSpeed = getTotalWindSpeed();
+ int gWindXSpeedMax = getWindXSpeedMax();
+ int gWindYSpeedMax = getWindYSpeedMax();
+ int bigXSize = getBigXSize();
+ int bigYSize = getBigYSize();
+
+ int groundAltitude = 0;
+ int totalSpeed = 0;
+ int resultingPoint = 0;
+ int unscaledXLoc = 0;
+ int unscaledYLoc = 0;
+ int terrainType = 0;
+ int passedBeyondUnit = 0;
+ int currentDist = 0;
+
+
+ if (!numSteps)
+ numSteps = 1;
+
+ if (!sXSpeed && !sYSpeed) {
+ sZSpeed = (static_cast<int>(.70711 * power)) ;
+ sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed)) ;
+ sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed)) ;
+
+ sZSpeed *= SCALE_Z;
+
+ sZLoc = (getGroundAltitude(x, y) + HEIGHT_LOW + 10) * SCALE_Z;
+
+ sXLoc = x * SCALE_X;
+ sYLoc = y * SCALE_Y;
+
+ sFrictionCount = 0;
+ sWhichRadius = NODE_DETECT_RADIUS + 1;
+
+ sWhichUnit = getClosestUnit(x + 10, y, 30, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 0, 0);
+ }
+
+ for (int i = 1; i <= numSteps; i++) {
+ unscaledXLoc = sXLoc / SCALE_X;
+ unscaledYLoc = sYLoc / SCALE_Y;
+
+ groundAltitude = getGroundAltitude(unscaledXLoc, unscaledYLoc);
+ groundAltitude *= SCALE_Z;
+
+ sZLoc += sZSpeed / SCALE_Z;
+
+ resultingPoint = MAX(1, unscaledXLoc + unscaledYLoc * getMaxX());
+
+ if (sZLoc <= groundAltitude) {
+ terrainType = getTerrain(unscaledXLoc, unscaledYLoc);
+
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ if (terrainType == TERRAIN_TYPE_GOOD)
+ return resultingPoint;
+ else
+ return 0 - resultingPoint;
+ } else {
+ if (checkIfWaterState(unscaledXLoc, unscaledYLoc)) {
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ return 0 - resultingPoint;
+ } else {
+ int cfco = 0;
+ int cfuo = 0;
+ int cfes = 0;
+ int cfao = 0;
+ cfao = checkForAngleOverlap(sWhichUnit, angle);
+
+ cfco = checkForCordOverlap(unscaledXLoc, unscaledYLoc, sWhichRadius, 1);
+ cfuo = checkForUnitOverlap(unscaledXLoc, unscaledYLoc, sWhichRadius, sWhichUnit);
+
+ if (!isEnergy)
+ cfes = checkForEnergySquare(unscaledXLoc, unscaledYLoc);
+
+ if (cfco || cfuo || cfes || cfao) {
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ return 0 - resultingPoint;
+ } else {
+ sFrictionCount++;
+
+ if (sFrictionCount == 10) {
+ sFrictionCount = 0;
+
+ if (!gWindXSpeed)
+ sXSpeed = sXSpeed * .95;
+
+ if (!gWindYSpeed)
+ sYSpeed = sYSpeed * .95;
+ }
+
+ if (passedBeyondUnit) {
+ totalSpeed = getDistance(0, 0, sXSpeed, sYSpeed);
+
+ if (totalSpeed > gTotalWindSpeed) {
+ if (gWindXSpeed > 0) {
+ if (sXSpeed < gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ } else {
+ if (sXSpeed > gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ }
+
+ if (gWindYSpeed > 0) {
+ if (sYSpeed < gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ } else {
+ if (sYSpeed > gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ }
+ }
+ } else {
+ currentDist = getDistance(unscaledXLoc, unscaledYLoc, x, y);
+
+ if (currentDist > BUILDING_HUB_RADIUS + NODE_DIAMETER)
+ passedBeyondUnit = 1;
+ }
+
+ sXLoc += sXSpeed;
+ sYLoc += sYSpeed;
+
+ limitLocation(sXLoc, sYLoc, bigXSize, bigYSize);
+
+ sZSpeed -= GRAVITY_CONSTANT;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int AI::simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
+ static int sXSpeed = 0;
+ static int sYSpeed = 0;
+ static int sZSpeed = 0;
+ static int sXLoc = 0;
+ static int sYLoc = 0;
+ static int sZLoc = 0;
+ static int sFrictionCount = 0;
+
+ int gWindXSpeed = getWindXSpeed();
+ int gWindYSpeed = getWindYSpeed();
+ int gTotalWindSpeed = getTotalWindSpeed();
+ int gWindXSpeedMax = getWindXSpeedMax();
+ int gWindYSpeedMax = getWindYSpeedMax();
+ int bigXSize = getBigXSize();
+ int bigYSize = getBigYSize();
+
+ int groundAltitude = 0;
+ int totalSpeed = 0;
+ int resultingPoint = 0;
+ int unscaledXLoc = 0;
+ int unscaledYLoc = 0;
+ int terrainType = 0;
+ int passedBeyondUnit = 0;
+ int currentDist = 0;
+
+ if (!numSteps) numSteps = 1;
+
+ if (!sXSpeed && !sYSpeed) {
+ sZSpeed = (static_cast<int>(.70711 * power)) ;
+ sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed)) ;
+ sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed)) ;
+
+ sZSpeed *= SCALE_Z;
+
+ sZLoc = (getGroundAltitude(x, y) + HEIGHT_LOW + 10) * SCALE_Z;
+
+ sXLoc = x * SCALE_X;
+ sYLoc = y * SCALE_Y;
+
+ sFrictionCount = 0;
+ }
+
+ for (int i = 1; i <= numSteps; i++) {
+ unscaledXLoc = sXLoc / SCALE_X;
+ unscaledYLoc = sYLoc / SCALE_Y;
+
+ groundAltitude = getGroundAltitude(unscaledXLoc, unscaledYLoc);
+ groundAltitude *= SCALE_Z;
+ sZLoc += sZSpeed / SCALE_Z;
+ resultingPoint = MAX(1, unscaledXLoc + unscaledYLoc * getMaxX());
+
+ if (sZLoc <= groundAltitude) {
+ terrainType = getTerrain(unscaledXLoc, unscaledYLoc);
+
+ sXSpeed = 0;
+ sYSpeed = 0;
+ sFrictionCount = 0;
+
+ if (terrainType == TERRAIN_TYPE_GOOD)
+ return resultingPoint;
+ else
+ return 0 - resultingPoint;
+ } else {
+ sFrictionCount++;
+
+ if (sFrictionCount == 10) {
+ sFrictionCount = 0;
+
+ if (!gWindXSpeed)
+ sXSpeed = sXSpeed * .95;
+
+ if (!gWindYSpeed)
+ sYSpeed = sYSpeed * .95;
+ }
+
+ if (passedBeyondUnit) {
+ totalSpeed = getDistance(0, 0, sXSpeed, sYSpeed);
+
+ if (totalSpeed > gTotalWindSpeed) {
+ if (gWindXSpeed > 0) {
+ if (sXSpeed < gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ } else {
+ if (sXSpeed > gWindXSpeedMax)
+ sXSpeed += gWindXSpeed;
+ }
+
+ if (gWindYSpeed > 0) {
+ if (sYSpeed < gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ } else {
+ if (sYSpeed > gWindYSpeedMax)
+ sYSpeed += gWindYSpeed;
+ }
+ }
+ } else {
+ currentDist = getDistance(unscaledXLoc, unscaledYLoc, x, y);
+
+ if (currentDist > BUILDING_HUB_RADIUS + NODE_DIAMETER)
+ passedBeyondUnit = 1;
+ }
+
+ sXLoc += sXSpeed;
+ sYLoc += sYSpeed;
+
+ limitLocation(sXLoc, sYLoc, bigXSize, bigYSize);
+
+ sZSpeed -= GRAVITY_CONSTANT;
+ }
+ }
+
+ return 0;
+}
+
+int AI::fakeSimulateWeaponLaunch(int x, int y, int power, int angle) {
+ int distance = power * 480 / getMaxPower();
+ float radAngle = degToRad(angle);
+ int maxX = getMaxX();
+ int maxY = getMaxY();
+
+ x += distance * cos(radAngle);
+ y += distance * sin(radAngle);
+
+ x = (x + maxX) % maxX;
+ y = (y + maxY) % maxY;
+
+ return MAX(1, x + y * maxX);
+}
+
+int AI::getEnergyHogType() {
+ return _energyHogType;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
new file mode 100644
index 0000000000..7a38de9458
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -0,0 +1,211 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_MAIN_H
+#define SCUMM_HE_MOONBASE_AI_MAIN_H
+
+#include "common/array.h"
+#include "scumm/he/moonbase/ai_tree.h"
+
+namespace Scumm {
+
+class ScummEngine_v100he;
+class AIEntity;
+class patternList;
+
+enum {
+ TERRAIN_TYPE_GOOD = 0,
+ TERRAIN_TYPE_SLOPE = 1,
+ TERRAIN_TYPE_WATER = 2,
+ MAX_MEMORY = 3
+};
+
+enum {
+ ITEM_BOMB = 0,
+ ITEM_CLUSTER = 1,
+ ITEM_REPAIR = 2,
+ ITEM_ANTIAIR = 3,
+ ITEM_BRIDGE = 4,
+ ITEM_TOWER = 5,
+ ITEM_GUIDED = 6,
+ ITEM_EMP = 7,
+ ITEM_SPIKE = 8,
+ ITEM_RECLAIMER = 9,
+ ITEM_BALLOON = 10,
+ ITEM_MINE = 11,
+ ITEM_CRAWLER = 12,
+ ITEM_VIRUS = 13,
+ ITEM_ENERGY = 14,
+ ITEM_SHIELD = 15,
+ ITEM_OFFENSE = 16,
+ ITEM_HUB = 17,
+ ITEM_TIME_EXPIRED = 18,
+ SKIP_TURN = -999
+};
+
+enum BuildingTypes {
+ BUILDING_ENERGY_COLLECTOR = 3,
+ BUILDING_MAIN_BASE = 4,
+ BUILDING_BRIDGE = 5,
+ BUILDING_TOWER = 6,
+ BUILDING_EXPLOSIVE_MINE = 7,
+ BUILDING_SHIELD = 8,
+ BUILDING_ANTI_AIR = 9,
+ BUILDING_OFFENSIVE_LAUNCHER = 10,
+ BUILDING_BALLOON = 11,
+ BUILDING_CRAWLER = 12
+};
+
+enum {
+ ENERGY_POOL_X = 45,
+ ENERGY_POOL_Y = 46,
+ ENERGY_POOL_UNITS_ON = 47,
+
+ MIN_DIST = 108
+};
+
+class AI {
+public:
+ AI(ScummEngine_v100he *vm);
+
+ void resetAI();
+ void cleanUpAI();
+ void setAIType(const int paramCount, const int32 *params);
+ int masterControlProgram(const int paramCount, const int32 *params);
+
+private:
+ int chooseBehavior();
+ int chooseTarget(int behavior);
+
+ Tree *initApproachTarget(int targetX, int targetY, Node **retNode);
+ int *approachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
+ Tree *initAcquireTarget(int targetX, int targetY, Node **retNode);
+ int *acquireTarget(int targetX, int targetY);
+ int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
+ int *offendTarget(int &targetX, int &targetY, int index);
+ int *defendTarget(int &targetX, int &targetY, int index);
+ int *energizeTarget(int &targetX, int &targetY, int index);
+
+public:
+ int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
+ int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
+
+ int getDistance(int originX, int originY, int endX, int endY);
+ int calcAngle(int originX, int originY, int endX, int endY);
+ int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
+ int getTerrain(int x, int y);
+
+ int getHubX(int hub);
+ int getHubY(int hub);
+ int getMaxX();
+ int getMaxY();
+
+ int getCurrentPlayer();
+ int getMaxPower();
+ int getMinPower();
+ int getTerrainSquareSize();
+ int getBuildingOwner(int building);
+ int getBuildingState(int building);
+ int getBuildingType(int building);
+ int getBuildingArmor(int building);
+ int getBuildingMaxArmor(int building);
+ int getBuildingWorth(int building);
+ int getBuildingTeam(int building);
+
+ int getPlayerEnergy();
+ int getPlayerMaxTime();
+ int getTimerValue(int timerNum);
+ int getPlayerTeam(int player);
+
+ int getAnimSpeed();
+
+ int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
+
+ int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
+ int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
+ int checkIfWaterState(int x, int y);
+ int getUnitsWithinRadius(int x, int y, int radius);
+
+ float degToRad(float degrees);
+
+ int getEnergyHogType();
+
+private:
+ int getEnergyPoolsArray();
+ int getCoordinateVisibility(int x, int y, int playerNum);
+ int getUnitVisibility(int unit, int playerNum);
+ int getEnergyPoolVisibility(int pool, int playerNum);
+ int getNumberOfPools();
+ int getNumberOfPlayers();
+ int getWindXSpeed();
+ int getWindYSpeed();
+ int getTotalWindSpeed();
+ int getWindXSpeedMax();
+ int getWindYSpeedMax();
+ int getBigXSize();
+ int getBigYSize();
+ int getEnergyPoolWidth(int pool);
+ int getLastAttacked(int &x, int &y);
+ int getFOW();
+ int getBuildingStackPtr();
+ int getTurnCounter();
+
+ int getGroundAltitude(int x, int y);
+ int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
+ int checkForAngleOverlap(int unit, int angle);
+ int estimateNextRoundEnergy(int player);
+ int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit);
+ int checkForEnergySquare(int x, int y);
+ int aiChat();
+
+ int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
+ int fakeSimulateWeaponLaunch(int x, int y, int power, int angle);
+
+ int checkIfWaterSquare(int x, int y);
+
+ int getLandingPoint(int x, int y, int power, int angle);
+ int getEnemyUnitsVisible(int playerNum);
+
+ void limitLocation(int &a, int &b, int c, int d);
+ int energyPoolSize(int pool);
+ int getMaxCollectors(int pool);
+
+public:
+ Common::Array<int> _lastXCoord[5];
+ Common::Array<int> _lastYCoord[5];
+
+ ScummEngine_v100he *_vm;
+
+ AIEntity *_aiType[5];
+
+ int _aiState;
+ int _behavior;
+ int _energyHogType;
+
+ patternList *_moveList[5];
+
+ const int32 *_mcpParams;
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_node.cpp b/engines/scumm/he/moonbase/ai_node.cpp
new file mode 100644
index 0000000000..083a156a31
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_node.cpp
@@ -0,0 +1,153 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+IContainedObject::IContainedObject(IContainedObject &sourceContainedObject) {
+ _objID = sourceContainedObject.getObjID();
+ _valueG = sourceContainedObject.getG();
+}
+
+int Node::_nodeCount = 0;
+
+Node::Node() {
+ _parent = NULL;
+ _depth = 0;
+ _nodeCount++;
+ _contents = NULL;
+}
+
+Node::Node(Node *sourceNode) {
+ _parent = NULL;
+ _children = sourceNode->getChildren();
+
+ _depth = sourceNode->getDepth();
+
+ _contents = sourceNode->getContainedObject()->duplicate();
+}
+
+Node::~Node() {
+ if (_contents != NULL) {
+ delete _contents;
+ _contents = NULL;
+ }
+
+ _nodeCount--;
+}
+
+int Node::generateChildren() {
+ int numChildren = _contents->numChildrenToGen();
+
+ int numChildrenGenerated = numChildren;
+ int errorCode = -1;
+ static int i = 0;
+
+ while (i < numChildren) {
+ Node *tempNode = new Node;
+ _children.push_back(tempNode);
+ tempNode->setParent(this);
+ tempNode->setDepth(_depth + 1);
+
+ int completionFlag;
+
+ IContainedObject *thisContObj = _contents->createChildObj(i, completionFlag);
+ assert(!(thisContObj != NULL && completionFlag == 0));
+
+ if (!completionFlag) {
+ _children.pop_back();
+ delete tempNode;
+ return 0;
+ }
+
+ i++;
+
+ if (thisContObj != NULL) {
+ tempNode->setContainedObject(thisContObj);
+ } else {
+ _children.pop_back();
+ delete tempNode;
+ numChildrenGenerated--;
+ }
+ }
+
+ i = 0;
+
+ if (numChildrenGenerated > 0)
+ return numChildrenGenerated;
+
+ return errorCode;
+}
+
+
+int Node::generateNextChild() {
+ int numChildren = _contents->numChildrenToGen();
+
+ static int i = 0;
+
+ Node *tempNode = new Node;
+ _children.push_back(tempNode);
+ tempNode->setParent(this);
+ tempNode->setDepth(_depth + 1);
+
+ int compFlag;
+ IContainedObject *thisContObj = _contents->createChildObj(i, compFlag);
+
+ if (thisContObj != NULL) {
+ tempNode->setContainedObject(thisContObj);
+ } else {
+ _children.pop_back();
+ delete tempNode;
+ }
+
+ ++i;
+
+ if (i > numChildren)
+ i = 0;
+
+ return i;
+}
+
+Node *Node::popChild() {
+ Node *temp;
+
+ temp = _children.back();
+ _children.pop_back();
+ return temp;
+}
+
+Node *Node::getFirstStep() {
+ Node *currentNode = this;
+
+ if (currentNode->getParent() == NULL)
+ return currentNode;
+
+ while (currentNode->getParent()->getParent() != NULL)
+ currentNode = currentNode->getParent();
+
+ assert(currentNode->getDepth() == 1);
+
+ return currentNode;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_node.h b/engines/scumm/he/moonbase/ai_node.h
new file mode 100644
index 0000000000..0c3ef2f023
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_node.h
@@ -0,0 +1,103 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_NODE_H
+#define SCUMM_HE_MOONBASE_AI_NODE_H
+
+#include "common/array.h"
+
+namespace Scumm {
+
+const float SUCCESS = -1;
+const float FAILURE = 1e20f;
+
+class IContainedObject {
+private:
+ int _objID;
+ float _valueG;
+
+protected:
+ virtual float getG() const { return _valueG; }
+ virtual float calcH() { return 0; }
+
+public:
+ IContainedObject() { _valueG = 0; _objID = -1; }
+ IContainedObject(float inG) { _valueG = inG; _objID = -1; }
+ IContainedObject(IContainedObject &sourceContainedObject);
+ virtual ~IContainedObject() {}
+
+ virtual IContainedObject *duplicate() = 0;
+
+ void setValueG(float inG) { _valueG = inG; }
+ float getValueG() { return _valueG; }
+
+ int getObjID() const { return _objID; }
+ void setObjID(int inputObjID) { _objID = inputObjID; }
+
+ virtual int numChildrenToGen() = 0;
+ virtual IContainedObject *createChildObj(int index, int &completionFlag) = 0;
+
+ virtual int checkSuccess() = 0;
+ virtual float calcT() { return getG(); }
+
+ float returnG() const { return getG(); }
+};
+
+class Node {
+private:
+ Node *_parent;
+ Common::Array<Node *> _children;
+
+ int _depth;
+ static int _nodeCount;
+
+ IContainedObject *_contents;
+
+public:
+ Node();
+ Node(Node *sourceNode);
+ ~Node();
+
+ void setParent(Node *parentPtr) { _parent = parentPtr; }
+ Node *getParent() const { return _parent; }
+
+ void setDepth(int depth) { _depth = depth; }
+ int getDepth() const { return _depth; }
+
+ static int getNodeCount() { return _nodeCount; }
+
+ void setContainedObject(IContainedObject *value) { _contents = value; }
+ IContainedObject *getContainedObject() { return _contents; }
+
+ Common::Array<Node *> getChildren() const { return _children; }
+ int generateChildren();
+ int generateNextChild();
+ Node *popChild();
+
+ float getObjectT() { return _contents->calcT(); }
+
+ Node *getFirstStep();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_pattern.h b/engines/scumm/he/moonbase/ai_pattern.h
new file mode 100644
index 0000000000..ae1fa6b55e
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_pattern.h
@@ -0,0 +1,162 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_PATTERN_H
+#define SCUMM_HE_MOONBASE_AI_PATTERN_H
+
+namespace Scumm {
+
+const int NO_PATTERN = 0;
+const int PATTERN_FOUND = 1;
+
+class patternInstance {
+private:
+ int _sourceHub;
+ int _unit;
+ int _power;
+ int _angle;
+
+public:
+ patternInstance() {
+ _sourceHub = 0;
+ _unit = 0;
+ _power = 0;
+ _angle = 0;
+ }
+
+ patternInstance(int sh, int unit, int power, int angle) {
+ setSourceHub(sh);
+ setUnit(unit);
+ setPower(power);
+ setAngle(angle);
+ }
+
+ void setSourceHub(int sh) { _sourceHub = sh; }
+ void setUnit(int unit) { _unit = unit; }
+
+ void setPower(int power) {
+ if (power < 300)
+ _power = 1;
+ else if (power < 480)
+ _power = 2;
+ else
+ _power = 3;
+ }
+
+ void setAngle(int angle) {
+ int tempAngle = angle % 360;
+
+ if ((tempAngle >= 0) && (tempAngle < 90))
+ _angle = 1;
+
+ if ((tempAngle >= 90) && (tempAngle < 180))
+ _angle = 2;
+
+ if ((tempAngle >= 180) && (tempAngle < 270))
+ _angle = 3;
+
+ if ((tempAngle >= 270))
+ _angle = 4;
+ }
+
+ int getSourceHub() const { return _sourceHub; }
+ int getUnit() const { return _unit; }
+ int getPowerIndex() const { return _power; }
+ int getAngleIndex() const { return _angle; }
+
+ static int comparePatterns(patternInstance *p1, patternInstance *p2) {
+ if (p1->getSourceHub() != p2->getSourceHub())
+ return 0;
+
+ if (p1->getUnit() != p2->getUnit())
+ return 0;
+
+ if (p1->getUnit() == -999)
+ return 0;
+
+ int temp = abs(p1->getPowerIndex() - p2->getPowerIndex());
+
+ if (temp > 1)
+ return 0;
+
+ temp = abs(p1->getAngleIndex() - p2->getAngleIndex());
+
+ if (temp > 1 && temp < 3)
+ return 0;
+
+ return 1;
+ }
+};
+
+class patternList {
+private:
+ patternInstance *theList[10];
+ int listIndex;
+
+public:
+ patternList() {
+ for (int i = 0; i < 10; i++) {
+ theList[i] = new patternInstance();
+ }
+
+ listIndex = 0;
+ }
+ ~patternList() {
+ for (int i = 0; i < 10; i++) {
+ delete theList[i];
+ }
+ }
+
+ void addPattern(int sh, int unit, int power, int angle) {
+ theList[listIndex]->setSourceHub(sh);
+ theList[listIndex]->setUnit(unit);
+ theList[listIndex]->setPower(power);
+ theList[listIndex]->setAngle(angle);
+
+ listIndex++;
+
+ if (listIndex > 9)
+ listIndex = 0;
+ }
+
+ int evaluatePattern(int sh, int unit, int power, int angle) {
+ patternInstance *patternToMatch = new patternInstance(sh, unit, power, angle);
+ int matchCount = 0;
+
+ for (int i = 0; i < 9; i++) {
+ if (patternInstance::comparePatterns(theList[i], patternToMatch)) {
+ matchCount++;
+ }
+ }
+
+ delete patternToMatch;
+
+ if (matchCount > 2)
+ return PATTERN_FOUND;
+
+ return NO_PATTERN;
+ }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.cpp b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
new file mode 100644
index 0000000000..313ea7a411
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
@@ -0,0 +1,566 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+
+#include "scumm/he/moonbase/ai_targetacquisition.h"
+#include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/ai_weapon.h"
+
+namespace Scumm {
+
+int Sortie::_sSourceX = 0;
+int Sortie::_sSourceY = 0;
+
+int Sortie::_sTargetX = 0;
+int Sortie::_sTargetY = 0;
+
+Sortie::~Sortie() {
+ for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); k++) {
+ delete *k;
+ }
+}
+
+void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY) {
+ DefenseUnit *thisUnit;
+ int currentPlayer = _ai->getCurrentPlayer();
+
+ for (int i = 0; i < 200; i++) {
+ int thisElement = _ai->_vm->_moonbase->readFromArray(enemyDefensesScummArray, 0, i);
+
+ if (thisElement) {
+ if (_ai->getBuildingOwner(thisElement)) {
+ if (_ai->getPlayerTeam(currentPlayer) != _ai->getBuildingTeam(thisElement)) {
+ int type = _ai->getBuildingType(thisElement);
+
+ switch (type) {
+ case BUILDING_ANTI_AIR:
+ thisUnit = new AntiAirUnit(_ai);
+ break;
+
+ case BUILDING_SHIELD:
+ thisUnit = new ShieldUnit(_ai);
+ break;
+
+ case BUILDING_EXPLOSIVE_MINE:
+ if (_ai->getDistance(_ai->getHubX(thisElement), _ai->getHubY(thisElement), defendX, defendY) < 90)
+ thisUnit = new MineUnit(_ai);
+ else
+ thisUnit = NULL;
+
+ break;
+
+ case BUILDING_CRAWLER:
+ thisUnit = NULL;
+ break;
+
+ default:
+ thisUnit = NULL;
+ break;
+ }
+
+ if (thisUnit != NULL) {
+ thisUnit->setID(thisElement);
+ thisUnit->setPos(_ai->getHubX(thisElement), _ai->getHubY(thisElement));
+
+ if (_ai->getBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
+
+ _enemyDefenses.push_back(thisUnit);
+ }
+ }
+ }
+ } else {
+ i = 200;
+ }
+ }
+}
+
+int *Sortie::getShotPos() const {
+ int *retVal = new int[2];
+
+ retVal[0] = _shotPosX;
+ retVal[1] = _shotPosY;
+
+ return retVal;
+}
+
+int Sortie::numChildrenToGen() {
+ int retVal = MAX<uint>(_enemyDefenses.size(), 1) * NUM_SHOT_POSITIONS * NUM_WEAPONS;
+ return retVal;
+}
+
+IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
+ float thisDamage;
+ Sortie *retSortie = new Sortie(_ai);
+ int activeDefenses = 0;
+
+ Common::Array<DefenseUnit *> thisEnemyDefenses;
+
+ // Copy the defensive unit list from the parent
+ for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); k++) {
+ DefenseUnit *temp;
+
+ switch ((*k)->getType()) {
+ case DUT_ANTI_AIR:
+ temp = new AntiAirUnit(*k, _ai);
+ break;
+
+ case DUT_SHIELD:
+ temp = new ShieldUnit(*k, _ai);
+ break;
+
+ case DUT_MINE:
+ temp = new MineUnit(*k, _ai);
+ break;
+
+ case DUT_CRAWLER:
+ temp = new CrawlerUnit(*k, _ai);
+ break;
+
+ default:
+ temp = new ShieldUnit(*k, _ai);
+ break;
+ }
+
+ thisEnemyDefenses.push_back(temp);
+ }
+
+ // Calculate the current target from the index
+ DefenseUnit *currentTarget = *(thisEnemyDefenses.begin() + static_cast<int>(index / (NUM_WEAPONS * NUM_SHOT_POSITIONS)));
+
+ assert(currentTarget);
+
+ // Pick correct weapon according to index
+ Weapon *currentWeapon = new Weapon(currentTarget->selectWeapon(index % NUM_WEAPONS));
+ retSortie->setUnitType(currentWeapon->getTypeID());
+
+ // Calculate distance from target to source hub
+ int distance = _ai->getDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
+
+ // Pick correct shot position according to index
+ Common::Point *targetCoords;
+ targetCoords = currentTarget->createTargetPos((static_cast<int>(index / NUM_WEAPONS) % NUM_SHOT_POSITIONS), distance, currentWeapon->getTypeID(), getSourcePosX(), getSourcePosY());
+ retSortie->setShotPos(targetCoords->x, targetCoords->y);
+
+ // Set the g value based on cost of the weapon
+ retSortie->setValueG(getG() + currentWeapon->getCost());
+
+ int AAcounter = 3;
+
+ // Loop through defensive units, toggling anti-air units and deciding if this weapon will land safely
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+
+ // Check to see if we're within an active defense's radius
+ if ((distance < (*i)->getRadius()) && ((*i)->getState() == DUS_ON)) {
+ activeDefenses++;
+
+ // Turn off this anti-air and drop the coverage count
+ if (((*i)->getType() == DUT_ANTI_AIR)) {
+ (*i)->setState(DUS_OFF);
+
+ if (currentWeapon->getTypeID() == ITEM_CLUSTER)
+ AAcounter--;
+ else
+ AAcounter = 0;
+ }
+
+ // Essentially disable this weapon choice, due to its impact with a shield, or untriggered anti-air
+ if (((*i)->getType() == DUT_SHIELD) || !AAcounter) {
+ retSortie->setValueG(1000);
+ i = thisEnemyDefenses.end() - 1;
+ }
+ } else {
+ // Turn on any anti-airs that were off the previous turn
+ if (((*i)->getType() == DUT_ANTI_AIR) && ((*i)->getState() == DUS_OFF))
+ (*i)->setState(DUS_ON);
+ }
+ }
+
+ // Turn on all the non-anti-air units in preparation for emp's and the next turn
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+ if ((*i)->getType() != DUT_ANTI_AIR) {
+ (*i)->setState(DUS_ON);
+ }
+ }
+
+ // If this weapon is still valid
+ if (retSortie->getValueG() < 1000) {
+ // Apply emp effects and damage to all units in range of weapon
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ) {
+ // Special simulated crawler detonation location used, since it walks a bit
+ if (currentWeapon->getTypeID() == ITEM_CRAWLER)
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
+ // Normal detonation location used here
+ else {
+ distance = _ai->getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+ }
+
+ if (distance < currentWeapon->getRadius()) {
+ // Apply damage
+ thisDamage = currentWeapon->getDamage();
+
+ if ((AAcounter != 3) && (currentWeapon->getTypeID() == ITEM_CLUSTER))
+ thisDamage = 0;
+
+ if (!_ai->_vm->_rnd.getRandomNumber(4))
+ currentWeapon->setTypeID(ITEM_MINE);
+
+ (*i)->setDamage((int)thisDamage);
+
+ // Apply emp effect
+ if (currentWeapon->getTypeID() == ITEM_EMP) {
+ (*i)->setState(DUS_OFF);
+ }
+
+ // Remove destroyed defenses
+ if ((*i)->getArmor() <= 0) {
+ delete *i;
+ i = thisEnemyDefenses.erase(i);
+ } else {
+ i++;
+ }
+ } else {
+ i++;
+ }
+ }
+ }
+
+ retSortie->setEnemyDefenses(thisEnemyDefenses);
+
+ delete targetCoords;
+ delete currentWeapon;
+ return retSortie;
+}
+
+float Sortie::calcH() {
+ float retValue = 0;
+ Common::Array<DefenseUnit *> thisEnemyDefenses = getEnemyDefenses();
+
+ for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+ if ((*i)->getState() == DUS_ON) {
+ switch ((*i)->getType()) {
+ case DUT_ANTI_AIR:
+ retValue += 1;
+
+ case DUT_MINE:
+ retValue += 1;
+ break;
+
+ case DUT_SHIELD:
+ retValue += 1;
+ break;
+ }
+ }
+ }
+
+ return retValue;
+}
+
+int Sortie::checkSuccess() {
+ if (!_enemyDefenses.size())
+ return SUCCESS;
+
+ int targetX = getTargetPosX();
+ int targetY = getTargetPosY();
+
+ int targetCheck = 0;
+
+ for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); i++) {
+ if (((*i)->getState() == DUS_ON) && ((*i)->getType() != DUT_HUB)) {
+ return 0;
+ }
+
+ if (((*i)->getPosX() == targetX) && ((*i)->getPosY() == targetY)) targetCheck = 1;
+ }
+
+ if (!targetCheck)
+ return SUCCESS;
+
+ // If shot pos == target pos return SUCCESS;
+ if ((targetX == getShotPosX()) && (getTargetPosY() == getShotPosY())) {
+ return SUCCESS;
+ }
+
+ return 0;
+}
+
+float Sortie::calcT() {
+ return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS;
+}
+
+IContainedObject *Sortie::duplicate() {
+ return this;
+}
+
+
+void Sortie::printEnemyDefenses() {
+ for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); i++) {
+ warning("Unit %d - Type: %d, Armor: %d, Status: %d", (*i)->getID(), (*i)->getType(), static_cast<int>((*i)->getArmor()), (*i)->getState());
+ }
+}
+
+Defender::Defender(AI *ai) : _ai(ai) {
+ _sourceX = _sourceY = 0;
+ _targetX = _targetY = 0;
+ _sourceUnit = 0;
+ _power = 0;
+ _angle = 0;
+ _unit = 0;
+}
+
+int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index) {
+ int currentPlayer = _ai->getCurrentPlayer();
+
+ //get list of near hubs
+ int unitsArray = _ai->getUnitsWithinRadius(targetX + 5, targetY, 480);
+
+ const int NUM_HUBS = 10;
+ //Order on dist
+ int hubArray[NUM_HUBS] = { 0 };
+ int hubIndex = 0;
+
+ for (int i = 0; i < 200; i++) {
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray, 0, i);
+
+ if (thisUnit) {
+ if (((_ai->getBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (_ai->getBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER)) && (_ai->getBuildingOwner(thisUnit) == currentPlayer)) {
+ for (int j = 0; j < NUM_HUBS; j++) {
+ if (hubArray[j]) {
+ int distCurrent = _ai->getDistance(targetX, targetY, _ai->getHubX(thisUnit), _ai->getHubY(thisUnit));
+ int distSaved = _ai->getDistance(targetX, targetY, _ai->getHubX(hubArray[j]), _ai->getHubY(hubArray[j]));
+
+ if (distCurrent < distSaved) {
+ hubArray[hubIndex] = hubArray[j];
+ hubArray[j] = thisUnit;
+ hubIndex++;
+ j = 100;
+ }
+ } else {
+ hubArray[j] = thisUnit;
+ hubIndex++;
+ j = 100;
+ }
+ }
+ }
+ }
+
+ if (hubIndex >= NUM_HUBS) {
+ hubIndex = NUM_HUBS;
+ i = 200;
+ }
+ }
+
+ _ai->_vm->_moonbase->deallocateArray(unitsArray);
+
+ //Check if repair is needed
+ int targetUnit = _ai->getClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
+
+ if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (_ai->getBuildingTeam(targetUnit) == _ai->getPlayerTeam(currentPlayer))) {
+ int armor = _ai->getBuildingArmor(targetUnit);
+
+ if (armor < _ai->getBuildingMaxArmor(targetUnit)) {
+ unitsArray = _ai->getUnitsWithinRadius(targetX + 5, targetY, 170);
+ int defCount = 0;
+
+ for (int i = 0; i < 200; i++) {
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray, 0, i);
+
+ if (thisUnit) {
+ if (((_ai->getBuildingType(thisUnit) == BUILDING_SHIELD) || (_ai->getBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (_ai->getBuildingOwner(thisUnit) == currentPlayer) && (_ai->getBuildingState(thisUnit) == 0)) {
+ defCount++;
+ i = 200;
+ }
+ }
+ }
+
+ _ai->_vm->_moonbase->deallocateArray(unitsArray);
+
+ if (defCount) {
+ //repair
+ int hubUnit = _ai->getClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
+
+ if (hubUnit && (hubUnit != targetUnit)) {
+ int powAngle = abs(_ai->getPowerAngleFromPoint(_ai->getHubX(hubUnit), _ai->getHubY(hubUnit), targetX, targetY, 20));
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ setTargetX(targetX);
+ setTargetY(targetY);
+
+ setSourceUnit(hubUnit);
+ setUnit(ITEM_REPAIR);
+ setPower(power);
+ setAngle(angle);
+
+ return 1;
+ }
+ }
+ }
+ }
+
+ //For each hub
+ for (int i = 0; i < MIN(NUM_HUBS, hubIndex); i++) {
+ int hubX = _ai->getHubX(hubArray[i]);
+ int hubY = _ai->getHubY(hubArray[i]);
+ //get angle to hub
+ int directAngleToHub = 0;
+
+ //If this hub is the target
+ if ((hubX == targetX) && (hubY == targetY)) {
+ //make the angle seed point at the closest enemy
+ int enemyUnit = _ai->getClosestUnit(hubX, hubY, _ai->getMaxX(), currentPlayer, 0, 0, 0);
+ directAngleToHub = _ai->calcAngle(targetX, targetY, _ai->getHubX(enemyUnit), _ai->getHubY(enemyUnit));
+ } else {
+ directAngleToHub = _ai->calcAngle(targetX, targetY, hubX, hubY);
+ }
+
+ //Number of random chances to land
+ for (int j = 0; j < 3; j++) {
+ //Pick random angle and dist within semicircle (-90 to +90) and (40 to 150)
+ int randAngle = directAngleToHub + _ai->_vm->_rnd.getRandomNumber(179) - 90;
+ int randDist = _ai->_vm->_rnd.getRandomNumber(109) + 40;
+
+ int x = (int)(targetX + randDist * cos(_ai->degToRad(randAngle)));
+ int y = (int)(targetY + randDist * sin(_ai->degToRad(randAngle)));
+
+ int powAngle = _ai->getPowerAngleFromPoint(hubX, hubY, x, y, 20);
+
+ if (powAngle < 0)
+ continue;
+
+ int power = powAngle / 360;
+ int angle = powAngle - (power * 360);
+
+ int coords = 0;
+ coords = _ai->simulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
+
+ //if valid, return
+ if (coords > 0) {
+ //warning("The prospective launching hub for this defensive unit is: %d", hubArray[i]);
+
+ setSourceX(hubX);
+ setSourceY(hubY);
+ setTargetX((x + _ai->getMaxX()) % _ai->getMaxX());
+ setTargetY((y + _ai->getMaxY()) % _ai->getMaxY());
+ setSourceUnit(hubArray[i]);
+
+ int unitsArray2 = _ai->getUnitsWithinRadius(targetX + 5, targetY, 200);
+ int shieldCount = 0;
+
+ for (int k = 0; k < 200; k++) {
+ int thisUnit = _ai->_vm->_moonbase->readFromArray(unitsArray2, 0, k);
+
+ if (thisUnit) {
+ if ((_ai->getBuildingType(thisUnit) == BUILDING_SHIELD) && (_ai->getBuildingOwner(thisUnit) == currentPlayer))
+ shieldCount++;
+
+ if ((_ai->getBuildingType(thisUnit) == BUILDING_BRIDGE) && (_ai->getBuildingOwner(thisUnit) == currentPlayer)) {
+ shieldCount--;
+ shieldCount = MAX(-1, shieldCount);
+ }
+ }
+ }
+
+ if ((_ai->_vm->_rnd.getRandomNumber((int)pow(3.0f, shieldCount + 1) - 1) == 0) && (_ai->getPlayerEnergy() > 6))
+ setUnit(ITEM_SHIELD);
+ else
+ setUnit(ITEM_ANTIAIR);
+
+ setPower(power);
+ setAngle(angle);
+
+ _ai->_vm->_moonbase->deallocateArray(unitsArray2);
+ return 1;
+ }
+
+ if (coords < 0) {
+ //drop a bridge for the cord
+ int yCoord = -coords / _ai->getMaxX();
+ int xCoord = -coords - (yCoord * _ai->getMaxX());
+
+ if (_ai->checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = _ai->getTerrainSquareSize();
+ xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+ yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+ int xDist = xCoord - x;
+ int yDist = yCoord - y;
+ x = (int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))));
+ y = (int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))));
+
+ setTargetX(x);
+ setTargetY(y);
+
+ int nextUnit = _ai->getClosestUnit(x, y, 480, _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+ powAngle = _ai->getPowerAngleFromPoint(_ai->getHubX(nextUnit), _ai->getHubY(nextUnit), x, y, 15);
+
+ powAngle = abs(powAngle);
+ power = powAngle / 360;
+ angle = powAngle - (power * 360);
+
+ setSourceUnit(nextUnit);
+ setUnit(ITEM_BRIDGE);
+ setPower(power);
+ setAngle(angle);
+
+ return 1;
+ }
+ }
+ }
+ }
+
+ // Else create new hub
+ int count = 0;
+ int coords = 0;
+
+ if (hubIndex == 0) return -3;
+
+ do {
+ int sourceHub = hubArray[_ai->_vm->_rnd.getRandomNumber(hubIndex - 1)];
+
+ setSourceX(_ai->getHubX(sourceHub));
+ setSourceY(_ai->getHubY(sourceHub));
+ setSourceUnit(sourceHub);
+ setUnit(ITEM_HUB);
+ setPower(_ai->_vm->_rnd.getRandomNumber(299) + 200);
+ setAngle(_ai->_vm->_rnd.getRandomNumber(359));
+ count++;
+
+ if (count > (NUM_HUBS * 3)) break;
+
+ coords = _ai->simulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
+ } while (coords <= 0);
+
+ if (coords > 0) {
+ setTargetX(coords % _ai->getMaxX());
+ setTargetY(coords / _ai->getMaxX());
+ } else {
+ setTargetX(0);
+ setTargetY(0);
+ }
+
+ return -1;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.h b/engines/scumm/he/moonbase/ai_targetacquisition.h
new file mode 100644
index 0000000000..5e6cfed8bc
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.h
@@ -0,0 +1,152 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TARGETACQUISITION_H
+#define SCUMM_HE_MOONBASE_AI_TARGETACQUISITION_H
+
+#include "scumm/he/moonbase/ai_defenseunit.h"
+#include "scumm/he/moonbase/ai_node.h"
+#include "scumm/he/moonbase/ai_tree.h"
+
+namespace Scumm {
+
+const int NUM_IMPT_UNITS = 3;
+const int NUM_SHOT_POSITIONS = 1;
+const int NUM_WEAPONS = 3;
+
+class Sortie : public IContainedObject {
+private:
+ static int _sSourceX;
+ static int _sSourceY;
+
+ static int _sTargetX;
+ static int _sTargetY;
+
+ int _unitType;
+ int _shotPosX, _shotPosY;
+ Common::Array<DefenseUnit *> _enemyDefenses;
+ AI *_ai;
+
+public:
+ Sortie(AI *ai) { _ai = ai; _unitType = 0; _shotPosX = _shotPosY = 0; }
+ virtual ~Sortie();
+
+ static void setSourcePos(int x, int y) {
+ _sSourceX = x;
+ _sSourceY = y;
+ }
+ static void setTargetPos(int x, int y) {
+ _sTargetX = x;
+ _sTargetY = y;
+ }
+
+ void setUnitType(int unitType) { _unitType = unitType; }
+
+ void setShotPosX(int shotPosX) { _shotPosX = shotPosX; }
+ void setShotPosY(int shotPosY) { _shotPosY = shotPosY; }
+ void setShotPos(int shotPosX, int shotPosY) {
+ _shotPosX = shotPosX;
+ _shotPosY = shotPosY;
+ }
+
+ void setEnemyDefenses(Common::Array<DefenseUnit *> enemyDefenses) {
+ _enemyDefenses = enemyDefenses;
+ }
+ void setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY);
+
+ void printEnemyDefenses();
+
+ static int getSourcePosX() { return _sSourceX; }
+ static int getSourcePosY() { return _sSourceY; }
+ static int getTargetPosX() { return _sTargetX; }
+ static int getTargetPosY() { return _sTargetY; }
+
+ int getUnitType() const { return _unitType; }
+
+ int getShotPosX() const { return _shotPosX; }
+ int getShotPosY() const { return _shotPosY; }
+ int *getShotPos() const;
+
+ Common::Array<DefenseUnit *> getEnemyDefenses() const { return _enemyDefenses; }
+
+ virtual IContainedObject *duplicate();
+
+ virtual int numChildrenToGen();
+ virtual IContainedObject *createChildObj(int, int &completionFlag);
+
+
+ virtual float calcH();
+ virtual int checkSuccess();
+ virtual float calcT();
+};
+
+class Defender {
+private:
+ int _sourceX;
+ int _sourceY;
+ int _targetX;
+ int _targetY;
+ int _sourceUnit;
+ int _power;
+ int _angle;
+ int _unit;
+ AI *_ai;
+
+public:
+ Defender(AI *ai);
+ void setSourceX(int sourceX) { _sourceX = sourceX; }
+ void setSourceY(int sourceY) { _sourceY = sourceY; }
+ void setTargetX(int targetX) { _targetX = targetX; }
+ void setTargetY(int targetY) { _targetY = targetY; }
+ void setSourceUnit(int sourceUnit) { _sourceUnit = sourceUnit; }
+ void setPower(int power) { _power = power; }
+ void setAngle(int angle) { _angle = angle; }
+ void setUnit(int unit) { _unit = unit; }
+
+ int getSourceX() const { return _sourceX; }
+ int getSourceY() const { return _sourceY; }
+ int getTargetX() const { return _targetX; }
+ int getTargetY() const { return _targetY; }
+ int getSourceUnit() const { return _sourceUnit; }
+ int getPower() const { return _power; }
+ int getAngle() const { return _angle; }
+ int getUnit() const { return _unit; }
+
+ int calculateDefenseUnitPosition(int targetX, int targetY, int index);
+};
+
+class defenseUnitCompare {
+public:
+ bool operator()(DefenseUnit *x, DefenseUnit *y) {
+ //disabled units go at the end
+ if (x->getState() == DUS_OFF) {
+ warning("OFF");
+ return 0;
+ }
+
+ return x->getDistanceTo() < y->getDistanceTo();
+ }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp
new file mode 100644
index 0000000000..d6eea67b41
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_traveller.cpp
@@ -0,0 +1,279 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_traveller.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+int Traveller::_targetPosX = 0;
+int Traveller::_targetPosY = 0;
+int Traveller::_maxDist = 0;
+
+int Traveller::_numToGen = 0;
+int Traveller::_sizeAngleStep = 0;
+
+Traveller::Traveller(AI *ai) : _ai(ai) {
+ _waterFlag = 0;
+ setValueG(0);
+ unsetDisabled();
+
+ _sourceHub = 0;
+ _angleTo = 0;
+ _powerTo = 0;
+ _waterSourceX = 0;
+ _waterSourceY = 0;
+ _waterDestX = 0;
+ _waterDestY = 0;
+
+ _posX = _posY = 0;
+}
+
+Traveller::Traveller(int originX, int originY, AI *ai) : _ai(ai) {
+ _waterFlag = 0;
+ setValueG(0);
+ unsetDisabled();
+
+ _posX = originX;
+ _posY = originY;
+
+ _sourceHub = 0;
+ _angleTo = 0;
+ _powerTo = 0;
+ _waterSourceX = 0;
+ _waterSourceY = 0;
+ _waterDestX = 0;
+ _waterDestY = 0;
+}
+
+void Traveller::adjustPosX(int offsetX) {
+ int maxX = _ai->getMaxX();
+ int deltaX = _posX + offsetX;
+
+ if (deltaX < 0) _posX = maxX + deltaX;
+ else if (deltaX > maxX) _posX = deltaX - maxX;
+ else _posX = deltaX;
+}
+
+void Traveller::adjustPosY(int offsetY) {
+ int maxY = _ai->getMaxX();
+ int deltaY = _posY + offsetY;
+
+ if (deltaY < 0) _posY = maxY + deltaY;
+ else if (deltaY > maxY) _posY = deltaY - maxY;
+ else _posY = deltaY;
+}
+
+void Traveller::adjustXY(int offsetX, int offsetY) {
+ adjustPosX(offsetX);
+ adjustPosY(offsetY);
+}
+
+float Traveller::calcH() {
+ float retVal = 0;
+ // Calc dist from here to target
+ retVal = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY);
+ // Divide by _maxDist to get minimum number of jumps to goal
+ retVal /= static_cast<float>(_maxDist);
+
+ return retVal * 2.0;
+}
+
+int Traveller::numChildrenToGen() {
+ if (!_numToGen)
+ _numToGen = _ai->getAnimSpeed() + 2;
+
+ return _numToGen;
+}
+
+IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
+ static int nodeCount = 0;
+ static int completionState = 1;
+
+ if (!index) nodeCount = 0;
+
+ nodeCount++;
+
+ Traveller *retTraveller = new Traveller(_ai);
+
+ static int dir, angle, power;
+
+ if (completionState) {
+ // Calculate angle between here and target
+ int directAngle = 0;
+
+ if (_ai->getEnergyHogType())
+ directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
+ else
+ directAngle = _ai->calcAngle(_posX, _posY, _targetPosX, _targetPosY);
+
+ // Calculate the offset angle for this index
+ if (!_sizeAngleStep)
+ _sizeAngleStep = 52 - (_ai->getAnimSpeed() * 7);
+
+ dir = _sizeAngleStep * ((static_cast<int>(index / NUM_POWER_STEPS) + 1) >> 1);
+ // Calculate the sign value for the offset for this index
+ int orientation = dir * (((static_cast<int>(index / NUM_POWER_STEPS) % 2) << 1) - 1);
+ // Add the offset angle to the direct angle to target
+ angle = orientation + directAngle;
+
+ // Calculate power for this index
+ int maxPower = 0;
+ int directDist = _ai->getDistance(_posX, _posY, _targetPosX, _targetPosY);
+
+ if (directDist > _maxDist + 120)
+ maxPower = _ai->getMaxPower();
+ else
+ maxPower = (int)((static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * _ai->getMaxPower());
+
+ maxPower -= 70;
+ power = (int)(maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP)));
+ }
+
+ retTraveller->setAngleTo(angle);
+ retTraveller->setPowerTo(power);
+
+ // Set this object's position to the new one determined by the power and angle from above
+ static int lastSuccessful = 0;
+ int coords = 0;
+
+ if (!(index % NUM_POWER_STEPS) || (!lastSuccessful)) {
+ coords = _ai->simulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
+ lastSuccessful = 0;
+ } else {
+ completionState = 1;
+ lastSuccessful = 0;
+ }
+
+ if (!coords) {
+ completionFlag = 0;
+ completionState = 0;
+ delete retTraveller;
+ return NULL;
+ } else {
+ completionFlag = 1;
+ completionState = 1;
+ }
+
+ int whoseTurn = _ai->getCurrentPlayer();
+ int maxX = _ai->getMaxX();
+
+ // Check new position to see if landing is clear
+ if (coords > 0) {
+ int yCoord = coords / maxX;
+ int xCoord = coords - (yCoord * maxX);
+
+ int terrain = _ai->getTerrain(xCoord, yCoord);
+ assert(terrain == TERRAIN_TYPE_GOOD);
+
+ float pwr = _ai->getMinPower() * .3;
+ float cosine = cos((static_cast<float>(angle) / 360) * (2 * M_PI));
+ float sine = sin((static_cast<float>(angle) / 360) * (2 * M_PI));
+ int xParam = (int)(xCoord + (pwr * cosine));
+ int yParam = (int)(yCoord + (pwr * sine));
+
+ if (xParam < 0)
+ xParam += _ai->getMaxX();
+ else if (xParam > _ai->getMaxX())
+ xParam -= _ai->getMaxX();
+
+ if (yParam < 0)
+ yParam += _ai->getMaxY();
+ else if (yParam > _ai->getMaxY())
+ yParam -= _ai->getMaxY();
+
+ if (_ai->checkIfWaterState(xParam, yParam)) {
+ delete retTraveller;
+ return NULL;
+ }
+
+ retTraveller->setPosY(yCoord);
+ retTraveller->setPosX(xCoord);
+
+ // Iterate through the previous action list, making sure this one isn't on it
+ for (Common::Array<int>::iterator i = (_ai->_lastXCoord[whoseTurn]).begin(), j = (_ai->_lastYCoord[whoseTurn]).begin(); i != (_ai->_lastXCoord[whoseTurn]).end(); i++, j++) {
+ // Check if this shot is the same as the last time we tried
+ if ((*i == retTraveller->getPosX()) && (*j == retTraveller->getPosY())) {
+ retTraveller->setDisabled();
+ delete retTraveller;
+ return NULL;
+ }
+ }
+
+ retTraveller->setValueG(getG() + 7 + (dir * DIRECTION_WEIGHT));
+ lastSuccessful = 1;
+ } else {
+ int yCoord = -coords / maxX;
+ int xCoord = -coords - (yCoord * maxX);
+
+ // If landing fault is because of water, add 1 extra to g and turn on water flag. Also set coords, and adjust power to water fault location
+ if (_ai->checkIfWaterState(xCoord, yCoord)) {
+ int terrainSquareSize = _ai->getTerrainSquareSize();
+ xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+ yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+ int xDist = xCoord - _posX;
+ int yDist = yCoord - _posY;
+ retTraveller->setPosX((int)(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)))));
+ retTraveller->setPosY((int)(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)))));
+
+ int closestHub = _ai->getClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), _ai->getMaxX(), _ai->getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+
+ retTraveller->setWaterSourceX(_ai->getHubX(closestHub));
+ retTraveller->setWaterSourceY(_ai->getHubY(closestHub));
+ retTraveller->setWaterDestX(retTraveller->getPosX());
+ retTraveller->setWaterDestY(retTraveller->getPosY());
+
+ retTraveller->setPowerTo(power);
+ retTraveller->setAngleTo(angle);
+
+ retTraveller->setValueG(getG() + 10 + (dir * DIRECTION_WEIGHT));
+ retTraveller->enableWaterFlag();
+ } else {
+ // If not, set G to highest value
+ retTraveller->setDisabled();
+ delete retTraveller;
+ return NULL;
+ }
+ }
+
+ return retTraveller;
+}
+
+int Traveller::checkSuccess() {
+ if (_ai->getDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
+ return SUCCESS;
+
+ return 0;
+}
+
+float Traveller::calcT() {
+ assert(!_disabled);
+
+ if (_disabled) return FAILURE;
+
+ return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_traveller.h b/engines/scumm/he/moonbase/ai_traveller.h
new file mode 100644
index 0000000000..20e69eb76c
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_traveller.h
@@ -0,0 +1,123 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TRAVELER_H
+#define SCUMM_HE_MOONBASE_AI_TRAVELER_H
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+const int NUM_TO_GEN = 9;
+
+const int NUM_POWER_STEPS = 3;
+const double SIZE_POWER_STEP = .15;
+const int SIZE_ANGLE_STEP = 45;
+const int VARIATION_EXTENT = 3;
+const int DIRECTION_WEIGHT = 5;
+
+class Traveller : public IContainedObject {
+private:
+ static int _targetPosX;
+ static int _targetPosY;
+ static int _maxDist;
+
+ static int _numToGen;
+ static int _sizeAngleStep;
+
+ int _sourceHub;
+
+ int _posX;
+ int _posY;
+ int _angleTo;
+ int _powerTo;
+
+ int _disabled;
+ int _waterFlag;
+ int _waterSourceX;
+ int _waterSourceY;
+ int _waterDestX;
+ int _waterDestY;
+
+ AI *_ai;
+
+protected:
+ virtual float calcH();
+
+public:
+ Traveller(AI *ai);
+ Traveller(int originX, int originY, AI *ai);
+ ~Traveller() {}
+
+ IContainedObject *duplicate() { return this; }
+
+ static void setTargetPosX(int posX) { _targetPosX = posX; }
+ static void setTargetPosY(int posY) { _targetPosY = posY; }
+ static void setMaxDist(int maxDist) { _maxDist = maxDist; }
+
+ void setSourceHub(int sourceHub) { _sourceHub = sourceHub; }
+
+ void setPosX(int posX) { _posX = posX; }
+ void setPosY(int posY) { _posY = posY; }
+ void setAngleTo(int angleTo) { _angleTo = angleTo; }
+ void setPowerTo(int powerTo) { _powerTo = powerTo; }
+
+ void setWaterSourceX(int waterSourceX) { _waterSourceX = waterSourceX; }
+ void setWaterSourceY(int waterSourceY) { _waterSourceY = waterSourceY; }
+
+ void setWaterDestX(int waterDestX) { _waterDestX = waterDestX; }
+ void setWaterDestY(int waterDestY) { _waterDestY = waterDestY; }
+
+ int getSourceHub() const { return _sourceHub; }
+
+ int getPosX() const { return _posX; }
+ int getPosY() const { return _posY; }
+ int getAngleTo() const { return _angleTo; }
+ int getPowerTo() const { return _powerTo; }
+
+ int getWaterSourceX() const { return _waterSourceX; }
+ int getWaterSourceY() const { return _waterSourceY; }
+ int getWaterDestX() const { return _waterDestX; }
+ int getWaterDestY() const { return _waterDestY; }
+
+ void setDisabled() { _disabled = 1; }
+ void unsetDisabled() { _disabled = 0; }
+ int getDisabled() { return _disabled; }
+
+ void adjustPosX(int offsetX);
+ void adjustPosY(int offsetY);
+ void adjustXY(int offsetX, int offsetY);
+
+ void enableWaterFlag() { _waterFlag = 1; }
+ void disableWaterFlag() { _waterFlag = 0; }
+ int getWaterFlag() const { return _waterFlag; }
+
+ virtual int numChildrenToGen();
+ virtual IContainedObject *createChildObj(int, int &);
+
+ virtual int checkSuccess();
+ virtual float calcT();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_tree.cpp b/engines/scumm/he/moonbase/ai_tree.cpp
new file mode 100644
index 0000000000..d18536812b
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_tree.cpp
@@ -0,0 +1,245 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_tree.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+static int compareTreeNodes(const void *a, const void *b) {
+ if (((const TreeNode *)a)->value < ((const TreeNode *)b)->value)
+ return -1;
+ else if (((const TreeNode *)a)->value > ((const TreeNode *)b)->value)
+ return 1;
+ else
+ return 0;
+}
+
+Tree::Tree(AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ _maxDepth = MAX_DEPTH;
+ _maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+Tree::Tree(IContainedObject *contents, AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ pBaseNode->setContainedObject(contents);
+ _maxDepth = MAX_DEPTH;
+ _maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+Tree::Tree(IContainedObject *contents, int maxDepth, AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ pBaseNode->setContainedObject(contents);
+ _maxDepth = maxDepth;
+ _maxNodes = MAX_NODES;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+Tree::Tree(IContainedObject *contents, int maxDepth, int maxNodes, AI *ai) : _ai(ai) {
+ pBaseNode = new Node;
+ pBaseNode->setContainedObject(contents);
+ _maxDepth = maxDepth;
+ _maxNodes = maxNodes;
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+}
+
+void Tree::duplicateTree(Node *sourceNode, Node *destNode) {
+ Common::Array<Node *> vUnvisited = sourceNode->getChildren();
+
+ while (vUnvisited.size()) {
+ Node *newNode = new Node(*(vUnvisited.end()));
+ newNode->setParent(destNode);
+ (destNode->getChildren()).push_back(newNode);
+ duplicateTree(*(vUnvisited.end()), newNode);
+ vUnvisited.pop_back();
+ }
+}
+
+Tree::Tree(const Tree *sourceTree, AI *ai) : _ai(ai) {
+ pBaseNode = new Node(sourceTree->getBaseNode());
+ _maxDepth = sourceTree->getMaxDepth();
+ _maxNodes = sourceTree->getMaxNodes();
+ _currentMap = new Common::SortedArray<TreeNode *>(compareTreeNodes);
+ _currentNode = 0;
+ _currentChildIndex = 0;
+
+ duplicateTree(sourceTree->getBaseNode(), pBaseNode);
+}
+
+Tree::~Tree() {
+ // Delete all nodes
+ Node *pNodeItr = pBaseNode;
+
+ // Depth first traversal of nodes to delete them
+ while (pNodeItr != NULL) {
+ // If any children are left, move to one of them
+ if (!(pNodeItr->getChildren().empty())) {
+ pNodeItr = pNodeItr->popChild();
+ } else {
+ // Delete this node, and move up to the parent for further processing
+ Node *pTemp = pNodeItr;
+ pNodeItr = pNodeItr->getParent();
+ delete pTemp;
+ pTemp = NULL;
+ }
+ }
+
+ delete _currentMap;
+}
+
+Node *Tree::aStarSearch() {
+ Common::SortedArray<TreeNode *> mmfpOpen(compareTreeNodes);
+
+ Node *currentNode = NULL;
+ float currentT;
+
+ Node *retNode = NULL;
+
+ float temp = pBaseNode->getContainedObject()->calcT();
+
+ if (static_cast<int>(temp) != SUCCESS) {
+ mmfpOpen.insert(new TreeNode(pBaseNode->getObjectT(), pBaseNode));
+
+ while (mmfpOpen.size() && (retNode == NULL)) {
+ currentNode = mmfpOpen.front()->node;
+ mmfpOpen.erase(mmfpOpen.begin());
+
+ if ((currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes)) {
+ // Generate nodes
+ Common::Array<Node *> vChildren = currentNode->getChildren();
+
+ for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
+ IContainedObject *pTemp = (*i)->getContainedObject();
+ currentT = pTemp->calcT();
+
+ if (currentT == SUCCESS)
+ retNode = *i;
+ else
+ mmfpOpen.insert(new TreeNode(currentT, (*i)));
+ }
+ } else {
+ retNode = currentNode;
+ }
+ }
+ } else {
+ retNode = pBaseNode;
+ }
+
+ return retNode;
+}
+
+
+Node *Tree::aStarSearch_singlePassInit() {
+ Node *retNode = NULL;
+
+ _currentChildIndex = 1;
+
+ float temp = pBaseNode->getContainedObject()->calcT();
+
+ if (static_cast<int>(temp) != SUCCESS) {
+ _currentMap->insert(new TreeNode(pBaseNode->getObjectT(), pBaseNode));
+ } else {
+ retNode = pBaseNode;
+ }
+
+ return retNode;
+}
+
+Node *Tree::aStarSearch_singlePass() {
+ float currentT = 0.0;
+ Node *retNode = NULL;
+
+ static int maxTime = 0;
+
+ if (_currentChildIndex == 1) {
+ maxTime = _ai->getPlayerMaxTime();
+ }
+
+ if (_currentChildIndex) {
+ if (!(_currentMap->size())) {
+ retNode = _currentNode;
+ return retNode;
+ }
+
+ _currentNode = _currentMap->front()->node;
+ _currentMap->erase(_currentMap->begin());
+ }
+
+ if ((_currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes) && ((!maxTime) || (_ai->getTimerValue(3) < maxTime))) {
+ // Generate nodes
+ _currentChildIndex = _currentNode->generateChildren();
+
+ if (_currentChildIndex) {
+ Common::Array<Node *> vChildren = _currentNode->getChildren();
+
+ if (!vChildren.size() && !_currentMap->size()) {
+ _currentChildIndex = 0;
+ retNode = _currentNode;
+ }
+
+ for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
+ IContainedObject *pTemp = (*i)->getContainedObject();
+ currentT = pTemp->calcT();
+
+ if (currentT == SUCCESS) {
+ retNode = *i;
+ i = vChildren.end() - 1;
+ } else {
+ _currentMap->insert(new TreeNode(currentT, (*i)));
+ }
+ }
+
+ if (!(_currentMap->size()) && (currentT != SUCCESS)) {
+ assert(_currentNode != NULL);
+ retNode = _currentNode;
+ }
+ }
+ } else {
+ retNode = _currentNode;
+ }
+
+ return retNode;
+}
+
+int Tree::IsBaseNode(Node *thisNode) {
+ return (thisNode == pBaseNode);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_tree.h b/engines/scumm/he/moonbase/ai_tree.h
new file mode 100644
index 0000000000..45d4963bc1
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_tree.h
@@ -0,0 +1,84 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TREE_H
+#define SCUMM_HE_MOONBASE_AI_TREE_H
+
+#include "common/array.h"
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+const int MAX_DEPTH = 100;
+const int MAX_NODES = 1000000;
+
+class AI;
+
+struct TreeNode {
+ float value;
+ Node *node;
+
+ TreeNode(float v, Node *n) { value = v; node = n; }
+};
+
+class Tree {
+private:
+ Node *pBaseNode;
+
+ int _maxDepth;
+ int _maxNodes;
+
+ int _currentChildIndex;
+
+ Common::SortedArray<TreeNode *> *_currentMap;
+ Node *_currentNode;
+
+ AI *_ai;
+
+public:
+ Tree(AI *ai);
+ Tree(IContainedObject *contents, AI *ai);
+ Tree(IContainedObject *contents, int maxDepth, AI *ai);
+ Tree(IContainedObject *contents, int maxDepth, int maxNodes, AI *ai);
+ Tree(const Tree *sourceTree, AI *ai);
+ ~Tree();
+
+ void duplicateTree(Node *sourceNode, Node *destNode);
+
+ Node *getBaseNode() const { return pBaseNode; }
+ void setMaxDepth(int maxDepth) { _maxDepth = maxDepth; }
+ int getMaxDepth() const { return _maxDepth; }
+
+ void setMaxNodes(int maxNodes) { _maxNodes = maxNodes; }
+ int getMaxNodes() const { return _maxNodes; }
+
+ Node *aStarSearch();
+
+ Node *aStarSearch_singlePassInit();
+ Node *aStarSearch_singlePass();
+
+ int IsBaseNode(Node *thisNode);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_types.cpp b/engines/scumm/he/moonbase/ai_types.cpp
new file mode 100644
index 0000000000..e134f5ee12
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_types.cpp
@@ -0,0 +1,176 @@
+/* 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.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "scumm/he/moonbase/ai_types.h"
+
+namespace Scumm {
+
+AIEntity::AIEntity(int id) {
+ switch (id) {
+ default:
+ case BRUTAKAS:
+ warning("BRUTAKAS");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "BRUTAKAS");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case AGI:
+ warning("Agi");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Agi");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_MEDIUM;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_LARGE;
+ break;
+
+ case EL_GATO:
+ warning("El Gato de la Noche");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "El Gato de la Noche");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_MEDIUM;
+ break;
+
+ case PIXELAHT:
+ warning("Pixelaht");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Pixelaht");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_LARGE;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case CYBALL:
+ warning("cYbaLL");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "cYbaLL");
+ _behaviorVariation = AI_VAR_LARGE;
+ _targetVariation = AI_VAR_LARGE;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case NEEP:
+ warning("Neep! Neep!");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Neep! Neep!");
+ _behaviorVariation = AI_VAR_MEDIUM;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_LARGE;
+ break;
+
+ case WARCUPINE:
+ warning("WARcupine");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "WARcupine");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_LARGE;
+ _powerVariation = AI_VAR_MEDIUM;
+ break;
+
+ case AONE:
+ warning("aone");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "aone");
+ _behaviorVariation = AI_VAR_MEDIUM;
+ _targetVariation = AI_VAR_MEDIUM;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_MEDIUM;
+ break;
+
+ case SPANDO:
+ warning("S p a n d o");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "S p a n d o");
+ _behaviorVariation = AI_VAR_LARGE;
+ _targetVariation = AI_VAR_LARGE;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case ORBNU_LUNATEK:
+ warning("Bonur J Lunatek");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Bonur J Lunatek");
+ _behaviorVariation = AI_VAR_HUGE;
+ _targetVariation = AI_VAR_HUGE;
+ _angleVariation = AI_VAR_HUGE;
+ _powerVariation = AI_VAR_HUGE;
+ break;
+
+ case CRAWLER_CHUCKER:
+ warning("Le Chuckre des Crawlres");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Le Chuckre des Crawlres");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_MEDIUM;
+ _angleVariation = AI_VAR_MEDIUM;
+ _powerVariation = AI_VAR_LARGE;
+ break;
+
+ case ENERGY_HOG:
+ warning("Energy Hog");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Energy Hog\n");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+
+ case RANGER:
+ warning("Ranger");
+ _id = id;
+ _nameString = new char[64];
+ strcpy(_nameString, "Ranger\n");
+ _behaviorVariation = AI_VAR_SMALL;
+ _targetVariation = AI_VAR_SMALL;
+ _angleVariation = AI_VAR_SMALL;
+ _powerVariation = AI_VAR_SMALL;
+ break;
+ }
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_types.h b/engines/scumm/he/moonbase/ai_types.h
new file mode 100644
index 0000000000..bb16a737e9
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_types.h
@@ -0,0 +1,97 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TYPES_H
+#define SCUMM_HE_MOONBASE_AI_TYPES_H
+
+namespace Scumm {
+
+enum {
+ AGI = 1,
+ AONE = 2,
+ BRUTAKAS = 3,
+ CYBALL = 4,
+ EL_GATO = 5,
+ NEEP = 6,
+ ORBNU_LUNATEK = 7,
+ PIXELAHT = 8,
+ SPANDO = 9,
+ WARCUPINE = 10
+};
+
+enum {
+ CRAWLER_CHUCKER = 11,
+ ENERGY_HOG = 12,
+ RANGER = 13
+};
+
+enum {
+ AI_VAR_NONE = -1,
+ AI_VAR_SMALL = 0,
+ AI_VAR_MEDIUM = 1,
+ AI_VAR_LARGE = 2,
+ AI_VAR_HUGE = 5
+};
+
+enum {
+ AI_VAR_BASE_BEHAVIOR = 10,
+ AI_VAR_BASE_TARGET = 10,
+ AI_VAR_BASE_ANGLE = 2,
+ AI_VAR_BASE_POWER = 5
+};
+
+class AIEntity {
+private:
+ int _id;
+ char *_nameString;
+ int _behaviorVariation;
+ int _targetVariation;
+ int _angleVariation;
+ int _powerVariation;
+
+public:
+ AIEntity(int id);
+ ~AIEntity() {
+ if (_nameString) {
+ delete[] _nameString;
+ _nameString = 0;
+ }
+ }
+
+ int getID() const { return _id; }
+ char *getNameString() const { return _nameString; }
+ int getBehaviorVariation() const { return _behaviorVariation; }
+ int getTargetVariation() const { return _targetVariation; }
+ int getAngleVariation() const { return _angleVariation; }
+ int getPowerVariation() const { return _powerVariation; }
+
+ void setID(int id) { _id = id; }
+ void setNameString(char *nameString) { _nameString = nameString; }
+ void setBehaviorVariation(int behaviorVariation) { _behaviorVariation = behaviorVariation; }
+ void setTargetVariation(int targetVariation) { _targetVariation = targetVariation; }
+ void setAngleVariation(int angleVariation) { _angleVariation = angleVariation; }
+ void setPowerVariation(int powerVariation) { _powerVariation = powerVariation; }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_weapon.cpp b/engines/scumm/he/moonbase/ai_weapon.cpp
new file mode 100644
index 0000000000..ba50aae4d1
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_weapon.cpp
@@ -0,0 +1,88 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_weapon.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+Weapon::Weapon(int typeID) { //, float damage, int radius)
+ switch (typeID) {
+ default:
+ case ITEM_BOMB:
+ becomeBomb();
+ break;
+
+ case ITEM_CLUSTER:
+ becomeCluster();
+ break;
+
+ case ITEM_CRAWLER:
+ becomeCrawler();
+ break;
+
+ case ITEM_EMP:
+ becomeEMP();
+ break;
+
+ case ITEM_SPIKE:
+ becomeSpike();
+ break;
+ }
+}
+
+void Weapon::becomeBomb() {
+ _typeID = ITEM_BOMB;
+ _damage = 3;
+ _radius = 30;
+ _cost = 1;
+}
+
+void Weapon::becomeCluster() {
+ _typeID = ITEM_CLUSTER;
+ _damage = 1.5;
+ _radius = 20;
+ _cost = 1;
+}
+
+void Weapon::becomeCrawler() {
+ _typeID = ITEM_CRAWLER;
+ _damage = 4;
+ _radius = 180;
+ _cost = 7;
+}
+
+void Weapon::becomeEMP() {
+ _typeID = ITEM_EMP;
+ _damage = .1f;
+ _radius = 215;
+ _cost = 3;
+}
+
+void Weapon::becomeSpike() {
+ _typeID = ITEM_SPIKE;
+ _damage = 6;
+ _radius = 180;
+ _cost = 3;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_weapon.h b/engines/scumm/he/moonbase/ai_weapon.h
new file mode 100644
index 0000000000..55c710ccdf
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_weapon.h
@@ -0,0 +1,59 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_WEAPON_H
+#define SCUMM_HE_MOONBASE_AI_WEAPON_H
+
+namespace Scumm {
+
+class Weapon {
+private:
+ int _typeID;
+ float _damage;
+ int _radius;
+ int _cost;
+
+public:
+ Weapon() {}
+ Weapon(int typeID);
+ virtual ~Weapon() {}
+
+ void setTypeID(int typeID) { _typeID = typeID; }
+ void setDamage(float damage) { _damage = damage; }
+ void setRadius(int radius) { _radius = radius; }
+ void setCost(int cost) { _cost = cost; }
+
+ int getTypeID() { return _typeID; }
+ float getDamage() { return _damage; }
+ int getRadius() { return _radius; }
+ int getCost() { return _cost; }
+
+ void becomeBomb();
+ void becomeCluster();
+ void becomeCrawler();
+ void becomeEMP();
+ void becomeSpike();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/distortion.cpp b/engines/scumm/he/moonbase/distortion.cpp
new file mode 100644
index 0000000000..6b637d0565
--- /dev/null
+++ b/engines/scumm/he/moonbase/distortion.cpp
@@ -0,0 +1,218 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "engines/scumm/he/moonbase/moonbase.h"
+
+namespace Scumm {
+
+enum {
+ kBptHeaderSize = 8,
+
+ kReflectionClipped = 0,
+ kNotClipped = 1,
+ kSpecializedNotClipped = 2
+};
+
+static void blitDistortionCore(
+ Graphics::Surface *dstBitmap,
+ const int x, const int y,
+ const Graphics::Surface *distortionBitmap,
+ const Common::Rect *optionalclipRectPtr,
+ int transferOp,
+ const Graphics::Surface *srcBitmap,
+ Common::Rect *srcClipRect
+) {
+ Common::Rect clipRect(dstBitmap->w, dstBitmap->h);
+
+ if (optionalclipRectPtr)
+ if (!clipRect.intersects(*optionalclipRectPtr))
+ return;
+
+ clipRect.clip(*optionalclipRectPtr);
+
+ Common::Rect distortionRect(distortionBitmap->w, distortionBitmap->h);
+ Common::Rect dstRect(x, y, x + distortionRect.width(), y + distortionRect.height());
+
+ if (!dstRect.intersects(clipRect))
+ return;
+
+ dstRect.clip(clipRect);
+
+ distortionRect.moveTo(dstRect.left - x, dstRect.top - y);
+
+ const byte *distortionPtr = (const byte *)distortionBitmap->getBasePtr(distortionRect.left, distortionRect.top);
+ byte *dstPtr = (byte *)dstBitmap->getBasePtr(dstRect.left, dstRect.top);
+ int cw = dstRect.width();
+ int ch = dstRect.height();
+ int idx = dstRect.left;
+ int dy = dstRect.top;
+
+ int baseX, baseY;
+ const byte *srcData = (const byte *)srcBitmap->getBasePtr(0, 0);
+ int srcPitch = srcBitmap->pitch;
+
+ switch (transferOp) {
+ case kReflectionClipped:
+ case kNotClipped:
+ baseX = -(0x1f / 2); // Half range
+ baseY = -(0x1f / 2);
+ break;
+
+ case kSpecializedNotClipped:
+ default:
+ baseX = 0;
+ baseY = 0;
+ }
+
+ while (--ch >= 0) {
+ uint16 *d = (uint16 *)dstPtr;
+ const uint16 *is = (const uint16 *)distortionPtr;
+ int dx = idx;
+
+ for (int i = cw; --i >= 0;) {
+ uint16 p = READ_LE_UINT16(is);
+ int sx = baseX + dx + ((p >> 5) & 0x1f); // G color
+ int sy = baseY + dy + (p & 0x1f); // B color;
+
+ if (transferOp == kReflectionClipped) {
+ if (sx < srcClipRect->left)
+ sx -= (srcClipRect->left - sx);
+
+ if (sx > srcClipRect->right)
+ sx -= (sx - srcClipRect->right);
+
+ sx = MAX<int>(srcClipRect->left, MIN<int>(sx, srcClipRect->right));
+
+ if (sy < srcClipRect->top)
+ sy -= (srcClipRect->top - sy);
+
+ if (sy > srcClipRect->bottom)
+ sy -= (sy - srcClipRect->bottom);
+
+ sy = MAX<int>(srcClipRect->top, MIN<int>(sy, srcClipRect->bottom));
+ }
+
+ *d = *((const uint16 *)(srcData + sy * srcPitch + sx * 2));
+
+ ++d;
+ ++is;
+ ++dx;
+ }
+
+ dstPtr += dstBitmap->pitch;
+ distortionPtr += distortionBitmap->pitch;
+
+ ++dy;
+ }
+}
+
+void Moonbase::blitDistortion(byte *bufferData, const int bufferWidth, const int bufferHeight, const int bufferPitch,
+ const Common::Rect *optionalClippingRect, byte *dataStream, const int x, const int y, byte *altSourceBuffer) {
+ byte *sourcePixels = (altSourceBuffer) ? altSourceBuffer : bufferData;
+ Common::Rect dstLimitsRect(bufferWidth, bufferHeight);
+ Common::Rect clippedDstRect = dstLimitsRect;
+
+ if (optionalClippingRect) {
+ if (!dstLimitsRect.intersects(*optionalClippingRect))
+ return;
+ dstLimitsRect.clip(*optionalClippingRect);
+ } else {
+ clippedDstRect = dstLimitsRect;
+ }
+
+ int w = READ_LE_UINT16(dataStream + kBptHeaderSize + 0);
+ int h = READ_LE_UINT16(dataStream + kBptHeaderSize + 2);
+ Common::Rect srcLimitsRect(w, h);
+ Common::Rect clippedSrcRect = srcLimitsRect;
+ Common::Rect dstOperation(x, y, x + clippedSrcRect.width(), y + clippedSrcRect.height());
+
+ if (!clippedDstRect.intersects(dstOperation))
+ return;
+
+ clippedDstRect.clip(dstOperation);
+
+ int subBlockCount = READ_LE_UINT16(dataStream + kBptHeaderSize + 4);
+ byte *subBlockStream = dataStream + kBptHeaderSize + READ_LE_UINT32(dataStream + 4);
+ int cx1 = clippedDstRect.left;
+ int cy1 = clippedDstRect.top;
+ int cx2 = clippedDstRect.right - 1;
+ int cy2 = clippedDstRect.bottom - 1;
+
+ for (int i = 0; i < subBlockCount; i++) {
+ byte *blockData = subBlockStream;
+ uint32 blockSize = READ_LE_UINT32(blockData); blockData += 4;
+ subBlockStream += blockSize;
+ int xOffset = READ_LE_UINT16(blockData); blockData += 2;
+ int yOffset = READ_LE_UINT16(blockData); blockData += 2;
+ int width = READ_LE_UINT16(blockData); blockData += 2;
+ int height = READ_LE_UINT16(blockData); blockData += 2;
+ int l_reach = READ_LE_UINT16(blockData); blockData += 2;
+ int r_reach = READ_LE_UINT16(blockData); blockData += 2;
+ int t_reach = READ_LE_UINT16(blockData); blockData += 2;
+ int b_reach = READ_LE_UINT16(blockData); blockData += 2;
+ int distortionPitch = ((width * 2 + 7) / 8); // 2 for 555
+
+ if (width == 0 && height == 0)
+ continue;
+
+ Graphics::Surface dstBitmap;
+ dstBitmap.init(bufferWidth, bufferHeight, bufferPitch, bufferData, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+
+ Graphics::Surface srcBitmap;
+ srcBitmap.init(bufferWidth, bufferHeight, bufferPitch, sourcePixels, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+
+ Graphics::Surface distortionBitmap;
+ distortionBitmap.init(width, height, distortionPitch, blockData, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+
+ Common::Rect srcClipRect(cx1, cy1, cx2, cy2);
+ Common::Rect dstClipRect(cx1, cy1, cx2, cy2);
+
+ int src_x = (x + xOffset);
+ int src_y = (y + yOffset);
+
+ Common::Rect srcReach((src_x - l_reach), (src_y - t_reach), (src_x + r_reach), (src_y + b_reach));
+ Common::Rect srcLimits(srcBitmap.w, srcBitmap.h);
+
+ if (!srcLimits.intersects(srcClipRect))
+ return;
+
+ srcLimits.clip(srcClipRect);
+
+ if (!srcReach.intersects(srcLimits))
+ return;
+
+ srcReach.clip(srcLimits);
+
+ if (srcLimits.contains(srcReach)) {
+ if (srcBitmap.pitch == 1280) {
+ blitDistortionCore(&dstBitmap, src_x, src_y, &distortionBitmap, &dstClipRect, kSpecializedNotClipped, &srcBitmap, 0);
+ } else {
+ blitDistortionCore(&dstBitmap, src_x, src_y, &distortionBitmap, &dstClipRect, kNotClipped, &srcBitmap, 0);
+ }
+ } else {
+ blitDistortionCore(&dstBitmap, src_x, src_y, &distortionBitmap, &dstClipRect, kReflectionClipped, &srcBitmap, &srcLimits);
+ }
+ }
+}
+
+}
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
new file mode 100644
index 0000000000..15ababd321
--- /dev/null
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -0,0 +1,223 @@
+/* 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.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+Moonbase::Moonbase(ScummEngine_v100he *vm) : _vm(vm) {
+ initFOW();
+
+ _ai = new AI(_vm);
+}
+
+Moonbase::~Moonbase() {
+ delete _ai;
+}
+
+int Moonbase::readFromArray(int array, int y, int x) {
+ _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = array;
+
+ return _vm->readArray(_vm->VAR_U32_ARRAY_UNK, y, x);
+}
+
+void Moonbase::deallocateArray(int array) {
+ _vm->VAR(_vm->VAR_U32_ARRAY_UNK) = array;
+
+ return _vm->nukeArray(_vm->VAR_U32_ARRAY_UNK);
+}
+
+int Moonbase::callScummFunction(int scriptNumber, int paramCount,...) {
+ va_list va_params;
+ va_start(va_params, paramCount);
+ int args[25];
+
+ memset(args, 0, sizeof(args));
+
+ Common::String str;
+ str = Common::String::format("callScummFunction(%d, [", scriptNumber);
+
+ for (int i = 0; i < paramCount; i++) {
+ args[i] = va_arg(va_params, int);
+
+ str += Common::String::format("%d ", args[i]);
+ }
+ str += "])";
+
+ debug(0, "%s", str.c_str());
+
+
+ va_end(va_params);
+
+ _vm->runScript(scriptNumber, 0, 1, args);
+
+ return _vm->pop();
+}
+
+
+void Moonbase::blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
+ uint8 *wizd, int x, int y, int rawROP, int paramROP) {
+ bool premulAlpa = false;
+
+ if (rawROP == 1)
+ premulAlpa = true;
+
+ Common::Rect clippedDstRect(dstw, dsth);
+ if (clipBox) {
+ Common::Rect clip(clipBox->left, clipBox->top, clipBox->right, clipBox->bottom);
+ if (clippedDstRect.intersects(clip)) {
+ clippedDstRect.clip(clip);
+ } else {
+ return;
+ }
+ }
+
+ int width = READ_LE_UINT16(wizd + 0x8 + 0);
+ int height = READ_LE_UINT16(wizd + 0x8 + 2);
+
+ Common::Rect srcLimitsRect(width, height);
+ Common::Rect dstOperation(x, y, x + width, y + height);
+ if (!clippedDstRect.intersects(dstOperation))
+ return;
+ Common::Rect clippedRect = clippedDstRect.findIntersectingRect(dstOperation);
+
+ int cx = clippedRect.right - clippedRect.left;
+ int cy = clippedRect.bottom - clippedRect.top;
+
+ int sx = ((clippedRect.left - x) + srcLimitsRect.left);
+ int sy = ((clippedRect.top - y) + srcLimitsRect.top);
+
+ dst += clippedRect.top * dstPitch + clippedRect.left * 2;
+
+ int headerSize = READ_LE_UINT32(wizd + 0x4);
+ uint8 *dataPointer = wizd + 0x8 + headerSize;
+
+ for (int i = 0; i < sy; i++) {
+ uint16 lineSize = READ_LE_UINT16(dataPointer + 0);
+
+ dataPointer += lineSize;
+ }
+
+ for (int i = 0; i < cy; i++) {
+ uint16 lineSize = READ_LE_UINT16(dataPointer + 0);
+ uint8 *singlesOffset = READ_LE_UINT16(dataPointer + 2) + dataPointer;
+ uint8 *quadsOffset = READ_LE_UINT16(dataPointer + 4) + dataPointer;
+
+ int pixels = 0;
+ byte *dst1 = dst;
+ byte *codes = dataPointer + 6;
+
+ while (1) {
+ int code = *codes - 2;
+ codes++;
+
+ if (code <= 0) { // quad or single
+ uint8 *src;
+ int cnt;
+ if (code == 0) { // quad
+ src = quadsOffset;
+ quadsOffset += 8;
+ cnt = 4; // 4 pixels
+ } else { // single
+ src = singlesOffset;
+ singlesOffset += 2;
+ cnt = 1;
+ }
+
+ for (int c = 0; c < cnt; c++) {
+ if (pixels >= sx) {
+ if (rawROP == 1) { // MMX_PREMUL_ALPHA_COPY
+ WRITE_LE_UINT16(dst1, READ_LE_UINT16(src));
+ } else if (rawROP == 2) { // MMX_ADDITIVE
+ uint16 color = READ_LE_UINT16(src);
+ uint16 orig = READ_LE_UINT16(dst1);
+
+ uint32 r = MIN<uint32>(0x7c00, (orig & 0x7c00) + (color & 0x7c00));
+ uint32 g = MIN<uint32>(0x03e0, (orig & 0x03e0) + (color & 0x03e0));
+ uint32 b = MIN<uint32>(0x001f, (orig & 0x001f) + (color & 0x001f));
+ WRITE_LE_UINT16(dst1, (r | g | b));
+ } else if (rawROP == 5) { // MMX_CHEAP_50_50
+ uint16 color = (READ_LE_UINT16(src) >> 1) & 0x3DEF;
+ uint16 orig = (READ_LE_UINT16(dst1) >> 1) & 0x3DEF;
+ WRITE_LE_UINT16(dst1, (color + orig));
+ }
+ dst1 += 2;
+ }
+ src += 2;
+ pixels++;
+ }
+ } else { // skip
+ if ((code & 1) == 0) {
+ code >>= 1;
+
+ for (int j = 0; j < code; j++) {
+ if (pixels >= sx)
+ dst1 += 2;
+ pixels++;
+ }
+ } else { // special case
+ if (pixels >= sx) {
+ int alpha = code >> 1;
+ uint16 color = READ_LE_UINT16(singlesOffset);
+ uint32 orig = READ_LE_UINT16(dst1);
+
+ if (!premulAlpa) {
+ WRITE_LE_UINT16(dst1, color); // ENABLE_PREMUL_ALPHA = 0
+ } else {
+ if (alpha > 32) {
+ alpha -= 32;
+
+ uint32 oR = orig & 0x7c00;
+ uint32 oG = orig & 0x03e0;
+ uint32 oB = orig & 0x1f;
+ uint32 dR = ((((color & 0x7c00) - oR) * alpha) >> 5) + oR;
+ uint32 dG = ((((color & 0x3e0) - oG) * alpha) >> 5) + oG;
+ uint32 dB = ((((color & 0x1f) - oB) * alpha) >> 5) + oB;
+
+ WRITE_LE_UINT16(dst1, (dR & 0x7c00) | (dG & 0x3e0) | (dB & 0x1f));
+ } else {
+ uint32 pix = ((orig << 16) | orig) & 0x3e07c1f;
+ pix = (((pix * alpha) & 0xffffffff) >> 5) & 0x3e07c1f;
+ pix = ((pix >> 16) + pix + color) & 0xffff;
+ WRITE_LE_UINT16(dst1, pix);
+ }
+ }
+
+ dst1 += 2;
+ }
+ singlesOffset += 2;
+ pixels++;
+ }
+ }
+
+ if (pixels >= cx + sx)
+ break;
+ }
+
+ dataPointer += lineSize;
+ dst += dstPitch;
+ }
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
new file mode 100644
index 0000000000..71c03cb007
--- /dev/null
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -0,0 +1,113 @@
+/* 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.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_MOONBASE_H
+#define SCUMM_HE_MOONBASE_MOONBASE_H
+
+#ifdef ENABLE_HE
+
+#include "common/winexe_pe.h"
+
+namespace Scumm {
+
+class AI;
+
+class Moonbase {
+public:
+ Moonbase(ScummEngine_v100he *vm);
+ ~Moonbase();
+
+ int readFromArray(int array, int y, int x);
+ void deallocateArray(int array);
+ int callScummFunction(int scriptNumber, int paramCount,...);
+
+ void blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
+ uint8 *wizd, int srcx, int srcy, int rawROP, int paramROP);
+ void blitDistortion(byte *bufferData, const int bufferWidth, const int bufferHeight, const int bufferPitch,
+ const Common::Rect *optionalClippingRect, byte *dataStream, const int x, const int y, byte *altSourceBuffer);
+
+ // FOW Stuff
+ bool isFOW(int resNum, int state, uint32 conditionBits) {
+ return resNum == _fowSentinelImage && state == _fowSentinelState && conditionBits == _fowSentinelConditionBits;
+ }
+
+ void initFOW();
+ void releaseFOWResources();
+
+ bool setFOWImage(int id);
+
+ void setFOWInfo(int fowInfoArray, int downDim, int acrossDim, int viewX, int viewY, int clipX1,
+ int clipY1, int clipX2, int clipY2, int technique, int nFrame);
+
+
+ void renderFOW(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int flags);
+
+private:
+ int readFOWVisibilityArray(int array, int y, int x);
+ void renderFOWState(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int x, int y, int srcw, int srch, int state, int flags);
+
+public:
+ int _fowSentinelImage;
+ int _fowSentinelState;
+ uint32 _fowSentinelConditionBits;
+
+ AI *_ai;
+
+private:
+ ScummEngine_v100he *_vm;
+
+ int _fowFrameBaseNumber;
+ int _fowAnimationFrames;
+ int _fowCurrentFOWFrame;
+
+ int32 _fowTileW;
+ int32 _fowTileH;
+
+ uint8 *_fowImage;
+ int _fowClipX1;
+ int _fowClipY1;
+ int _fowClipX2;
+ int _fowClipY2;
+
+ int _fowDrawX;
+ int _fowDrawY;
+
+ int _fowVtx1;
+ int _fowVty1;
+ int _fowMvx;
+ int _fowMvy;
+ int _fowVw;
+ int _fowVh;
+
+ bool _fowBlackMode;
+
+ int32 _fowRenderTable[32768];
+
+ Common::PEResources _exe;
+ Common::String _fileName;
+};
+
+} // End of namespace Scumm
+
+#endif // ENABLE_HE
+
+#endif // SCUMM_HE_MOONBASE_H
diff --git a/engines/scumm/he/moonbase/moonbase_fow.cpp b/engines/scumm/he/moonbase/moonbase_fow.cpp
new file mode 100644
index 0000000000..0837d9eea3
--- /dev/null
+++ b/engines/scumm/he/moonbase/moonbase_fow.cpp
@@ -0,0 +1,423 @@
+/* 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.
+ *
+ */
+
+#include "common/config-manager.h"
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+
+namespace Scumm {
+
+#define FOW_ANIM_FRAME_COUNT 38
+
+void Moonbase::initFOW() {
+ _fowSentinelImage = -1;
+ _fowSentinelState = -1;
+ _fowSentinelConditionBits = 0;
+
+ _fowFrameBaseNumber = 0;
+ _fowAnimationFrames = 1;
+ _fowCurrentFOWFrame = 0;
+
+ _fowTileW = 0;
+ _fowTileH = 0;
+
+ _fowImage = nullptr;
+ _fowClipX1 = 0;
+ _fowClipY1 = 0;
+ _fowClipX2 = 0;
+ _fowClipY2 = 0;
+
+ _fowDrawX = 0;
+ _fowDrawY = 0;
+
+ _fowVtx1 = 0;
+ _fowVty1 = 0;
+ _fowMvx = 0;
+ _fowMvy = 0;
+ _fowVw = 0;
+ _fowVh = 0;
+
+ _fowBlackMode = true;
+
+ memset(_fowRenderTable, 0, sizeof(_fowRenderTable));
+}
+
+void Moonbase::releaseFOWResources() {
+ if (_fowImage) {
+ free(_fowImage);
+ _fowImage = 0;
+ }
+}
+
+bool Moonbase::setFOWImage(int image) {
+ releaseFOWResources();
+
+ if (!_fowImage) {
+ Common::String fowImageFilename(ConfMan.get("MOONX_FOWImageFilename").c_str());
+
+#if 0 // TODO
+ if (!fowImageFilename.empty()) {
+ void *wiz = loadWizFromFilename(fowImageFilename);
+
+ if (wiz) {
+ captureFOWImageFromLocation(wiz, file.size());
+ free(wiz);
+ }
+ }
+#endif
+
+ if (!_fowImage && image < 0) {
+ int resId;
+
+ // PIECES BUBBLES CIRCLES SIMPLE* WEDGEY BUBBLE2
+ // WEDGE2 SPIKEY ANGLES SMOOTHED WUZZY SYS7-BEVELED
+ if (image >= -12 && image <= -1)
+ resId = 210 - image; // 211-222 range
+ else
+ resId = 214; // default, SIMPLE
+
+ if (_fileName.empty()) { // We are running for the first time
+ _fileName = _vm->generateFilename(-3);
+
+ if (!_exe.loadFromEXE(_fileName))
+ error("Cannot open file %s", _fileName.c_str());
+ }
+
+ Common::SeekableReadStream *stream = _exe.getResource(Common::kPERCData, resId);
+
+ if (stream->size()) {
+ _fowImage = (uint8 *)malloc(stream->size());
+
+ stream->read(_fowImage, stream->size());
+ }
+
+ delete stream;
+ }
+
+ if (!_fowImage && image > 0) {
+ int sz = _vm->getResourceSize(rtImage, image);
+ _fowImage = (uint8 *)malloc(sz);
+
+ // We have to copy it, otherwise the resource manager
+ // will kill it earlier or later. Matches original.
+ memcpy(_fowImage, _vm->getResourceAddress(rtImage, image), sz);
+ }
+
+ if (!_fowImage)
+ return false;
+ }
+
+ int nStates = _vm->_wiz->getWizImageStates(_fowImage);
+
+ if (nStates > FOW_ANIM_FRAME_COUNT) {
+ releaseFOWResources();
+ return false;
+ }
+
+ _fowAnimationFrames = (nStates + FOW_ANIM_FRAME_COUNT - 1) / FOW_ANIM_FRAME_COUNT;
+
+ _vm->_wiz->getWizImageDim(_fowImage, (nStates - 1), _fowTileW, _fowTileH);
+ _fowBlackMode = !_vm->_wiz->isWizPixelNonTransparent(_fowImage, nStates - 1, 0, 0, 0);
+
+ if (ConfMan.hasKey("EnableFOWRects"))
+ _fowBlackMode = (ConfMan.getInt("EnableFOWRects") == 1);
+
+ return true;
+}
+
+enum FOWElement {
+ FOW_EMPTY = 0,
+ FOW_SOLID = 1,
+
+ FF_L = 0x01,
+ FF_R = 0x02,
+ FF_T = 0x04,
+ FF_B = 0x08,
+ FF_T_L = 0x10,
+ FF_T_R = 0x20,
+ FF_B_L = 0x40,
+ FF_B_R = 0x80,
+ FF_Q_A = (FF_L | FF_T | FF_T_L),
+ FF_Q_B = (FF_R | FF_T | FF_T_R),
+ FF_Q_C = (FF_L | FF_B | FF_B_L),
+ FF_Q_D = (FF_R | FF_B | FF_B_R)
+};
+
+int Moonbase::readFOWVisibilityArray(int array, int y, int x) {
+ if (readFromArray(array, x, y) > 0)
+ return FOW_EMPTY;
+
+ return FOW_SOLID;
+}
+
+void Moonbase::setFOWInfo(int fowInfoArray, int downDim, int acrossDim, int viewX, int viewY, int clipX1,
+ int clipY1, int clipX2, int clipY2, int technique, int nFrame) {
+ if (!_fowImage)
+ return;
+
+ memset(_fowRenderTable, 0, sizeof(_fowRenderTable));
+
+ _fowDrawX = clipX1;
+ _fowDrawY = clipY1;
+
+ _fowClipX1 = clipX1;
+ _fowClipY1 = clipY1;
+ _fowClipX2 = clipX2;
+ _fowClipY2 = clipY2;
+
+ // Figure out the number of tiles are involved
+ int view_W = (clipX2 - clipX1) + 1;
+ int view_H = (clipY2 - clipY1) + 1;
+
+ int tw = _fowTileW;
+ int th = _fowTileH;
+
+ int dw = acrossDim;
+ int dh = downDim;
+
+ int dlw = dw * tw;
+ int dlh = dh * th;
+
+ _fowMvx = (0 <= viewX) ? (viewX % dlw) : (dlw - (-viewX % dlw));
+ _fowMvy = (0 <= viewY) ? (viewY % dlh) : (dlh - (-viewY % dlh));
+
+ _fowVtx1 = _fowMvx / tw;
+ _fowVty1 = _fowMvy / th;
+
+ _fowVw = (((_fowMvx + view_W + tw - 1) / tw) - _fowVtx1) + 1;
+ _fowVh = (((_fowMvy + view_H + th - 1) / th) - _fowVty1) + 1;
+
+ // Build the connectivity table
+ int t = (_fowVty1 - 1); if (t >= dh) { t = 0; } else if (t < 0) { t = (dh - 1); }
+ int m = (_fowVty1 + 0); if (m >= dh) { m = 0; } else if (m < 0) { m = (dh - 1); }
+ int b = (_fowVty1 + 1); if (b >= dh) { b = 0; } else if (b < 0) { b = (dh - 1); }
+
+ int il = (_fowVtx1 - 1); if (il >= dh) { il = 0; } else if (il < 0) { il = (dw - 1); }
+ int ic = (_fowVtx1 + 0); if (ic >= dh) { ic = 0; } else if (ic < 0) { ic = (dw - 1); }
+ int ir = (_fowVtx1 + 1); if (ir >= dh) { ir = 0; } else if (ir < 0) { ir = (dw - 1); }
+
+ int dataOffset = (_fowVw * 3);
+ int dataOffset2 = (dataOffset * 2);
+ int32 *pOutterRenderTableA = _fowRenderTable;
+ int32 *pOutterRenderTableB = pOutterRenderTableA + dataOffset;
+
+ for (int ay = 0; ay < _fowVh; ay++) {
+ int l = il;
+ int c = ic;
+ int r = ir;
+
+ int32 *pRenderTableA = pOutterRenderTableA;
+ int32 *pRenderTableB = pOutterRenderTableB;
+
+ pOutterRenderTableA += dataOffset2;
+ pOutterRenderTableB += dataOffset2;
+
+ for (int ax = 0; ax < _fowVw; ax++) {
+ int visibility = readFOWVisibilityArray(fowInfoArray, m, c);
+
+ if (visibility == FOW_EMPTY) {
+ uint32 bits = 0;
+
+ if (readFOWVisibilityArray(fowInfoArray, t, l) != 0) bits |= FF_T_L;
+ if (readFOWVisibilityArray(fowInfoArray, t, c) != 0) bits |= FF_T;
+ if (readFOWVisibilityArray(fowInfoArray, t, r) != 0) bits |= FF_T_R;
+ if (readFOWVisibilityArray(fowInfoArray, m, l) != 0) bits |= FF_L;
+ if (readFOWVisibilityArray(fowInfoArray, m, r) != 0) bits |= FF_R;
+ if (readFOWVisibilityArray(fowInfoArray, b, l) != 0) bits |= FF_B_L;
+ if (readFOWVisibilityArray(fowInfoArray, b, c) != 0) bits |= FF_B;
+ if (readFOWVisibilityArray(fowInfoArray, b, r) != 0) bits |= FF_B_R;
+
+ if (bits) {
+ *pRenderTableA++ = 1;
+ *pRenderTableB++ = 1;
+
+ // Quadrant (A)
+ if (bits & FF_Q_A) {
+ *pRenderTableA++ = (
+ ((FF_L & bits) ? 1 : 0) |
+ ((FF_T & bits) ? 2 : 0) |
+ ((FF_T_L & bits) ? 4 : 0)
+ ) + 0;
+ } else {
+ *pRenderTableA++ = 0;
+ }
+
+ // Quadrant (B)
+ if (bits & FF_Q_B) {
+ *pRenderTableA++ = (
+ ((FF_R & bits) ? 1 : 0) |
+ ((FF_T & bits) ? 2 : 0) |
+ ((FF_T_R & bits) ? 4 : 0)
+ ) + 8;
+ } else {
+ *pRenderTableA++ = 0;
+ }
+
+ // Quadrant (C)
+ if (bits & FF_Q_C) {
+ *pRenderTableB++ = (
+ ((FF_L & bits) ? 1 : 0) |
+ ((FF_B & bits) ? 2 : 0) |
+ ((FF_B_L & bits) ? 4 : 0)
+ ) + 16;
+ } else {
+ *pRenderTableB++ = 0;
+ }
+
+ // Quadrant (D)
+ if (bits & FF_Q_D) {
+ *pRenderTableB++ = (
+ ((FF_R & bits) ? 1 : 0) |
+ ((FF_B & bits) ? 2 : 0) |
+ ((FF_B_R & bits) ? 4 : 0)
+ ) + 24;
+ } else {
+ *pRenderTableB++ = 0;
+ }
+ } else {
+ *pRenderTableA++ = 0;
+ *pRenderTableB++ = 0;
+ }
+ } else {
+ if (_fowBlackMode) {
+ *pRenderTableA++ = 2;
+ *pRenderTableB++ = 2;
+ } else {
+ *pRenderTableA++ = 1;
+ *pRenderTableA++ = 33;
+ *pRenderTableA++ = 34;
+
+ *pRenderTableB++ = 1;
+ *pRenderTableB++ = 35;
+ *pRenderTableB++ = 36;
+ }
+ }
+
+ if (++l >= dw) { l = 0; }
+ if (++c >= dw) { c = 0; }
+ if (++r >= dw) { r = 0; }
+ }
+
+ if (++t >= dh) { t = 0; }
+ if (++m >= dh) { m = 0; }
+ if (++b >= dh) { b = 0; }
+ }
+
+ _fowCurrentFOWFrame = (nFrame >= 0) ? (nFrame % _fowAnimationFrames) : ((-nFrame) % _fowAnimationFrames);
+ _fowFrameBaseNumber = (_fowCurrentFOWFrame * FOW_ANIM_FRAME_COUNT);
+}
+
+void Moonbase::renderFOWState(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int x, int y, int srcw, int srch, int state, int flags) {
+ int32 spotx, spoty;
+
+ _vm->_wiz->getWizImageSpot(_fowImage, state, spotx, spoty);
+ Common::Rect r(_fowClipX1, _fowClipY1, _fowClipX2, _fowClipY2);
+
+ _vm->_wiz->drawWizImageEx(destSurface, _fowImage, 0, dstPitch, dstType, dstw, dsth, x - spotx, y - spoty, srcw, srch, state, &r, flags, 0, 0, 16, 0, 0);
+}
+
+static void blackRect_16bpp(uint8 *destSurface, int dstPitch, int dstw, int dsth, int x1, int y1, int x2, int y2) {
+ byte *dst = destSurface + dstPitch * y1 + x1 * 2;
+ int h = y2 - y1;
+ int w = ((x2 - x1) + 1) * 2;
+
+ while (--h >= 0) {
+ memset(dst, 0, w);
+ dst += dstPitch;
+ }
+}
+
+void Moonbase::renderFOW(uint8 *destSurface, int dstPitch, int dstType, int dstw, int dsth, int flags) {
+ if (!_fowImage)
+ return;
+
+ const int32 *pOutterRenderTable = _fowRenderTable;
+ int ixPos = ((_fowVtx1 * _fowTileW) - _fowMvx) + _fowDrawX;
+ int yPos = ((_fowVty1 * _fowTileH) - _fowMvy) + _fowDrawY;
+ int dataOffset = _fowVw * 3;
+ int halfTileHeight = _fowTileH / 2;
+ int cx2 = MIN(_fowClipX2, (dstw - 1));
+ int cy2 = MIN(_fowClipY2, (dsth - 1));
+
+ for (int ry = 0; ry < _fowVh; ry++) {
+ int real_yPos = yPos;
+
+ for (int i = 0; i < 2; i++) {
+ const int32 *pRenderTable = pOutterRenderTable;
+ pOutterRenderTable += dataOffset;
+
+ int xPos = ixPos;
+
+ for (int rx = 0; rx < _fowVw; rx++) {
+ int nState = *pRenderTable++;
+
+ if (nState != 0) {
+ if (nState == 2) {
+ int countLeft = (_fowVw - rx);
+ int count = 0;
+
+ for (; count < countLeft; count++) {
+ if (*(pRenderTable + count) != 2)
+ break;
+
+ pRenderTable++;
+ rx++;
+ }
+ count++;
+
+ int x1 = xPos;
+ int y1 = real_yPos;
+
+ xPos += _fowTileW * count;
+ int x2 = (xPos - 1);
+ int y2 = ((y1 + halfTileHeight) - 1);
+
+ x1 = MAX(0, x1);
+ y1 = MAX(0, y1);
+ x2 = MIN(x2, cx2);
+ y2 = MIN(y2, cy2);
+
+ if ((x2 >= x1) && (y2 >= y1) && (x1 <= _fowClipX2) && (y1 <= _fowClipY2))
+ blackRect_16bpp(destSurface, dstPitch, dstw, dsth, x1, y1, x2, y2);
+ } else {
+ int subState;
+
+ if ((subState = *pRenderTable++) != 0)
+ renderFOWState(destSurface, dstPitch, dstType, dstw, dsth, xPos, yPos, _fowTileW, _fowTileH, (subState + _fowFrameBaseNumber), flags);
+
+ if ((subState = *pRenderTable++) != 0)
+ renderFOWState(destSurface, dstPitch, dstType, dstw, dsth, xPos, yPos, _fowTileW, _fowTileH, (subState + _fowFrameBaseNumber), flags);
+
+ xPos += _fowTileW;
+ }
+ } else {
+ xPos += _fowTileW;
+ }
+ }
+ real_yPos += halfTileHeight;
+ }
+ yPos += _fowTileH;
+ }
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index afc6633ef6..714f431188 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -184,7 +184,7 @@ void ScummEngine_v100he::setupOpcodes() {
OPCODE(0x74, o6_delay);
OPCODE(0x75, o6_delayMinutes);
OPCODE(0x76, o6_delaySeconds);
- OPCODE(0x77, o100_startSound);
+ OPCODE(0x77, o100_soundOps);
/* 78 */
OPCODE(0x78, o80_sourceDebug);
OPCODE(0x79, o100_setSpriteInfo);
@@ -356,38 +356,38 @@ void ScummEngine_v100he::o100_actorOps() {
// FIXME: check stack parameters
debug(0,"o100_actorOps: case 0 UNHANDLED");
break;
- case 3:
+ case 3: // SO_ANIMATION
pop();
pop();
pop();
break;
- case 4: // SO_ANIMATION_SPEED
+ case 4: // SO_ANIMATION_SPEED
a->setAnimSpeed(pop());
break;
- case 6:
+ case 6: // SO_AT
j = pop();
i = pop();
a->putActor(i, j);
break;
- case 8:
+ case 8: // SO_BACKGROUND_OFF
a->_drawToBackBuf = false;
a->_needRedraw = true;
a->_needBgReset = true;
break;
- case 9:
+ case 9: // SO_BACKGROUND_ON
a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
break;
- case 14:
+ case 14: // SO_CHARSET
a->_charset = pop();
break;
- case 18:
+ case 18: // SO_CLIPPED
a->_clipOverride.bottom = pop();
a->_clipOverride.right = pop();
a->_clipOverride.top = pop();
a->_clipOverride.left = pop();
adjustRect(a->_clipOverride);
break;
- case 22:
+ case 22: // SO_CONDITION
k = getStackList(args, ARRAYSIZE(args));
for (i = 0; i < k; ++i) {
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
@@ -399,7 +399,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 27: // SO_DEFAULT
a->initActor(0);
break;
- case 32:
+ case 32: // SO_ERASE
k = pop();
a->setHEFlag(1, k);
break;
@@ -417,11 +417,11 @@ void ScummEngine_v100he::o100_actorOps() {
a->remapActorPaletteColor(i, j);
a->_needRedraw = true;
break;
- case 59:
+ case 59: // SO_PRIORITY
a->_layer = pop();
a->_needRedraw = true;
break;
- case 63:
+ case 63: // SO_ROOM_PALETTE
a->_hePaletteNum = pop();
a->_needRedraw = true;
break;
@@ -438,7 +438,7 @@ void ScummEngine_v100he::o100_actorOps() {
i = pop();
a->setActorWalkSpeed(i, j);
break;
- case 78:
+ case 78: // SO_TALKIE
{
copyScriptString(string, sizeof(string));
int slot = pop();
@@ -461,7 +461,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 89: // SO_NEVER_ZCLIP
a->_forceClip = 0;
break;
- case 128:
+ case 128: // SO_ACTOR_DEFAULT_CLIPPED
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
@@ -517,7 +517,7 @@ void ScummEngine_v100he::o100_actorOps() {
case 141: // SO_TALK_COLOR
a->_talkColor = pop();
break;
- case 142:
+ case 142: // SO_TALK_CONDITION
k = pop();
if (k == 0)
k = _rnd.getRandomNumberRng(1, 10);
@@ -549,20 +549,20 @@ void ScummEngine_v100he::o100_arrayOps() {
debug(9,"o100_arrayOps: array %d case %d", array, subOp);
switch (subOp) {
- case 35:
+ case 35: // SO_FORMATTED_STRING
decodeScriptString(string);
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
memcpy(data, string, len);
break;
- case 77: // SO_ASSIGN_STRING
+ case 77: // SO_STRING
copyScriptString(string, sizeof(string));
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
memcpy(data, string, len);
break;
- case 128: // SO_ASSIGN_2DIM_LIST
+ case 128: // SO_ASSIGN_2DIM_LIST
len = getStackList(list, ARRAYSIZE(list));
id = readVar(array);
if (id == 0)
@@ -572,7 +572,7 @@ void ScummEngine_v100he::o100_arrayOps() {
writeArray(array, c, len, list[len]);
}
break;
- case 129: // SO_ASSIGN_INT_LIST
+ case 129: // SO_ASSIGN_INT_LIST
b = pop();
c = pop();
id = readVar(array);
@@ -583,7 +583,7 @@ void ScummEngine_v100he::o100_arrayOps() {
writeArray(array, 0, b + c, pop());
}
break;
- case 130:
+ case 130: // SO_COMPLEX_ARRAY_ASSIGNMENT
len = getStackList(list, ARRAYSIZE(list));
dim1end = pop();
dim1start = pop();
@@ -607,7 +607,7 @@ void ScummEngine_v100he::o100_arrayOps() {
dim2start++;
}
break;
- case 131:
+ case 131: // SO_COMPLEX_ARRAY_COPY_OPERATION
{
int a2_dim1end = pop();
int a2_dim1start = pop();
@@ -624,44 +624,79 @@ void ScummEngine_v100he::o100_arrayOps() {
copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
}
break;
- case 132:
- // TODO: Used by room 2 script 2180 in Moonbase Commander
- fetchScriptWord();
- fetchScriptWord();
- type = pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- pop();
- dim1end = pop();
- dim1start = pop();
- dim2end = pop();
- dim2start = pop();
- id = readVar(array);
- if (id == 0) {
- defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end);
- }
- switch (type) {
- case 1:
- break;
- case 2:
- break;
- case 3:
- break;
- case 4:
- break;
- case 5:
+ case 132: // SO_COMPLEX_ARRAY_MATH_OPERATION
+ {
+ // Used by room 2 script 2180 in Moonbase Commander (modify-line-of-sight)
+ int array2 = fetchScriptWord();
+ int array1 = fetchScriptWord();
+ type = pop();
+ int a1_dim1end = pop();
+ int a1_dim1start = pop();
+ int a1_dim2end = pop();
+ int a1_dim2start = pop();
+ int a2_dim1end = pop();
+ int a2_dim1start = pop();
+ int a2_dim2end = pop();
+ int a2_dim2start = pop();
+ dim1end = pop();
+ dim1start = pop();
+ dim2end = pop();
+ dim2start = pop();
+
+ debug(0, "Complex: %d = %d[%d to %d][%d to %d] %c %d[%d to %d][%d to %d]", array,
+ array1, a1_dim1start, a1_dim2end, a1_dim1start, a1_dim2end,
+ " +-&|^"[type],
+ array2, a2_dim1start, a2_dim2end, a2_dim1start, a2_dim2end);
+
+ int a12_num = a1_dim2end - a1_dim2start + 1;
+ int a11_num = a1_dim1end - a1_dim1start + 1;
+ int a22_num = a2_dim2end - a2_dim2start + 1;
+ int a21_num = a2_dim1end - a2_dim1start + 1;
+ int d12_num = dim2end - dim2start + 1;
+ int d11_num = dim1end - dim1start + 1;
+
+ id = readVar(array);
+ if (id == 0) {
+ defineArray(array, kDwordArray, dim2start, dim2end, dim1start, dim1end);
+ }
+ if (a12_num != a22_num || a12_num != d12_num || a11_num != a21_num || a11_num != d11_num) {
+ error("Operation size mismatch (%d vs %d)(%d vs %d)", a12_num, a22_num, a11_num, a21_num);
+ }
+
+ for (; a1_dim2start <= a1_dim2end; ++a1_dim2start, ++a2_dim2start, ++dim2start) {
+ int a2dim1 = a2_dim1start;
+ int a1dim1 = a1_dim1start;
+ int dim1 = dim1start;
+ for (; a1dim1 <= a1_dim1end; ++a1dim1, ++a2dim1, ++dim1) {
+ int val1 = readArray(array1, a1_dim2start, a1dim1);
+ int val2 = readArray(array2, a2_dim2start, a2dim1);
+ int res;
+
+ switch (type) {
+ case 1: // Addition
+ res = val2 + val1;
+ break;
+ case 2: // Subtraction
+ res = val2 - val1;
+ break;
+ case 3: // Binary AND
+ res = val2 & val1;
+ break;
+ case 4: // Binary OR
+ res = val2 | val1;
+ break;
+ case 5: // Binary XOR
+ res = val2 ^ val1;
+ break;
+ default:
+ error("o100_arrayOps: case 132 unknown type %d)", type);
+ }
+ writeArray(array, dim2start, dim1, res);
+ }
+ }
break;
- default:
- error("o100_arrayOps: case 132 unknown type %d)", type);
}
- debug(0, "o100_arrayOps: case 132 type %d", type);
- break;
- case 133:
+ case 133: // SO_RANGE_ARRAY_ASSIGNMENT
b = pop();
c = pop();
dim1end = pop();
@@ -910,10 +945,10 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 0:
+ case 0: // SO_INIT
_curSpriteGroupId = pop();
break;
- case 6:
+ case 6: // SO_MOVE
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -921,7 +956,7 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->setGroupPosition(_curSpriteGroupId, value1, value2);
break;
- case 18:
+ case 18: // SO_CLIPPED
value4 = pop();
value3 = pop();
value2 = pop();
@@ -931,10 +966,10 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4);
break;
- case 38:
+ case 38: // SO_GROUP
type = pop() - 1;
switch (type) {
- case 0:
+ case 0: // SPRGRPOP_MOVE
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -942,48 +977,48 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->moveGroupMembers(_curSpriteGroupId, value1, value2);
break;
- case 1:
+ case 1: // SPRGRPOP_ORDER
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersPriority(_curSpriteGroupId, value1);
break;
- case 2:
+ case 2: // SPRGRPOP_NEW_GROUP
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersGroup(_curSpriteGroupId, value1);
break;
- case 3:
+ case 3: // SPRGRPOP_UPDATE_TYPE
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1);
break;
- case 4:
+ case 4: // SPRGRPOP_NEW
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersResetSprite(_curSpriteGroupId);
break;
- case 5:
+ case 5: // SPRGRPOP_ANIMATION_SPEED
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1);
break;
- case 6:
+ case 6: // SPRGRPOP_ANIMATION_TYPE
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1);
break;
- case 7:
+ case 7: // SPRGRPOP_SHADOW
value1 = pop();
if (!_curSpriteGroupId)
break;
@@ -994,14 +1029,14 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
error("o100_setSpriteGroupInfo subOp 38: Unknown case %d", subOp);
}
break;
- case 40:
+ case 40: // SO_IMAGE
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupImage(_curSpriteGroupId, value1);
break;
- case 49:
+ case 49: // SO_AT
value2 = pop();
value1 = pop();
if (!_curSpriteGroupId)
@@ -1009,51 +1044,51 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
_sprite->moveGroup(_curSpriteGroupId, value1, value2);
break;
- case 52:
+ case 52: // SO_NAME
copyScriptString(string, sizeof(string));
break;
- case 53:
+ case 53: // SO_NEW
if (!_curSpriteGroupId)
break;
_sprite->resetGroup(_curSpriteGroupId);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
// dummy case
pop();
pop();
break;
- case 59:
+ case 59: // SO_PRIORITY
value1 = pop();
if (!_curSpriteGroupId)
break;
_sprite->setGroupPriority(_curSpriteGroupId, value1);
break;
- case 60:
+ case 60: // SO_PROPERTY
type = pop();
value1 = pop();
if (!_curSpriteGroupId)
break;
switch (type) {
- case 0:
+ case 0: // SPRGRPPROP_XMUL
_sprite->setGroupXMul(_curSpriteGroupId, value1);
break;
- case 1:
+ case 1: // SPRGRPPROP_XDIV
_sprite->setGroupXDiv(_curSpriteGroupId, value1);
break;
- case 2:
+ case 2: // SPRGRPPROP_YMUL
_sprite->setGroupYMul(_curSpriteGroupId, value1);
break;
- case 3:
+ case 3: // SPRGRPPROP_YDIV
_sprite->setGroupYDiv(_curSpriteGroupId, value1);
break;
default:
error("o100_setSpriteGroupInfo subOp 60: Unknown case %d", subOp);
}
break;
- case 89:
+ case 89: // SO_NEVER_ZCLIP
if (!_curSpriteGroupId)
break;
@@ -1110,6 +1145,7 @@ void ScummEngine_v100he::o100_resourceRoutines() {
break;
case 128:
// TODO: Clear Heap
+ warning("STUB: o100_resourceRoutines: clear Heap");
break;
case 129:
// Dummy case
@@ -1310,36 +1346,36 @@ void ScummEngine_v100he::o100_wizImageOps() {
if (_wizParams.img.resNum)
_wiz->processWizImage(&_wizParams);
break;
- case 128:
- _wizParams.field_239D = pop();
- _wizParams.field_2399 = pop();
- _wizParams.field_23A5 = pop();
- _wizParams.field_23A1 = pop();
- copyScriptString(_wizParams.string2, sizeof(_wizParams.string2));
+ case 128: // Font create
_wizParams.processMode = 15;
+ _wizParams.fontProperties.bgColor = pop();
+ _wizParams.fontProperties.fgColor = pop();
+ _wizParams.fontProperties.size = pop();
+ _wizParams.fontProperties.style = pop();
+ copyScriptString(_wizParams.fontProperties.fontName, sizeof(_wizParams.fontProperties.fontName));
break;
case 129:
_wizParams.processMode = 14;
break;
- case 130:
+ case 130: // Font render
_wizParams.processMode = 16;
- _wizParams.field_23AD = pop();
- _wizParams.field_23A9 = pop();
- copyScriptString(_wizParams.string1, sizeof(_wizParams.string1));
+ _wizParams.fontProperties.yPos = pop();
+ _wizParams.fontProperties.xPos = pop();
+ copyScriptString(_wizParams.fontProperties.string, sizeof(_wizParams.fontProperties.string));
break;
case 131:
_wizParams.processMode = 13;
break;
- case 133:
+ case 133: // Render ellipse
_wizParams.processMode = 17;
- _wizParams.field_23CD = pop();
- _wizParams.field_23C9 = pop();
- _wizParams.field_23C5 = pop();
- _wizParams.field_23C1 = pop();
- _wizParams.field_23BD = pop();
- _wizParams.field_23B9 = pop();
- _wizParams.field_23B5 = pop();
- _wizParams.field_23B1 = pop();
+ _wizParams.ellipseProperties.color = pop();
+ _wizParams.ellipseProperties.lod = pop();
+ _wizParams.ellipseProperties.ky = pop();
+ _wizParams.ellipseProperties.kx = pop();
+ _wizParams.ellipseProperties.qy = pop();
+ _wizParams.ellipseProperties.qx = pop();
+ _wizParams.ellipseProperties.py = pop();
+ _wizParams.ellipseProperties.px = pop();
break;
case 134:
_wizParams.processFlags |= kWPFFillColor | kWPFClipBox2;
@@ -1584,13 +1620,13 @@ void ScummEngine_v100he::o100_roomOps() {
setPalColor(d, a, b, c);
break;
- case 129:
+ case 129: // SO_OBJECT_ORDER
b = pop();
a = pop();
swapObjects(a, b);
break;
- case 130:
+ case 130: // SO_ROOM_COPY_PALETTE
a = pop();
b = pop();
if (_game.features & GF_16BIT_COLOR)
@@ -1625,7 +1661,7 @@ void ScummEngine_v100he::o100_roomOps() {
setCurrentPalette(a);
break;
- case 135:
+ case 135: // SO_ROOM_PALETTE_IN_ROOM
b = pop();
a = pop();
setRoomPalette(a, b);
@@ -1637,7 +1673,7 @@ void ScummEngine_v100he::o100_roomOps() {
_saveLoadFlag = pop();
break;
- case 137:
+ case 137: // SO_ROOM_SAVEGAME_BY_NAME
byte buffer[256];
copyScriptString((byte *)buffer, sizeof(buffer));
@@ -1706,69 +1742,69 @@ void ScummEngine_v100he::o100_setSystemMessage() {
}
}
-void ScummEngine_v100he::o100_startSound() {
+void ScummEngine_v100he::o100_soundOps() {
byte filename[260];
int var, value;
byte subOp = fetchScriptByte();
switch (subOp) {
- case 6:
- _heSndFlags |= 16;
+ case 6: // SO_AT
+ _heSndFlags |= HE_SND_OFFSET;
_heSndOffset = pop();
break;
- case 47:
+ case 47: // SO_LOAD
copyScriptString(filename, sizeof(filename));
_heSndSoundId = pop();
if (_heSndSoundId)
debug(0, "Load sound %d from file %s\n", _heSndSoundId, filename);
break;
- case 55:
- _heSndFlags |= 8;
+ case 55: // SO_NOW
+ _heSndFlags |= HE_SND_QUICK_START;
break;
- case 83:
+ case 83: // SO_VARIABLE
value = pop();
var = pop();
_heSndSoundId = pop();
((SoundHE *)_sound)->setSoundVar(_heSndSoundId, var, value);
break;
- case 92:
- _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags);
+ case 92: // SO_END
+ _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags, _heSndSoundFreq, _heSndPan, _heSndVol);
break;
- case 128:
- _heSndFlags |= 2;
+ case 128: // SO_SOUND_ADD
+ _heSndFlags |= HE_SND_APPEND;
break;
- case 129:
+ case 129: // SO_SOUND_CHANNEL
_heSndChannel = pop();
break;
- case 130:
- _heSndFlags |= 64;
- pop();
+ case 130: // SO_SOUND_FREQUENCY
+ _heSndFlags |= HE_SND_FREQUENCY;
+ _heSndSoundFreq = pop();
break;
- case 131:
- _heSndFlags |= 1;
+ case 131: // SO_SOUND_LOOPING
+ _heSndFlags |= HE_SND_LOOP;
break;
- case 132: // Music
- case 134: // Sound
+ case 132: // SO_SOUND_MODIFY
+ case 134: // SO_SOUND_START
_heSndSoundId = pop();
_heSndOffset = 0;
_heSndSoundFreq = 11025;
_heSndChannel = VAR(VAR_SOUND_CHANNEL);
_heSndFlags = 0;
break;
- case 133:
- _heSndFlags |= 128;
- pop();
+ case 133: // SO_SOUND_PAN
+ _heSndFlags |= HE_SND_PAN;
+ _heSndPan = pop();
break;
- case 135:
- _heSndFlags |= 4;
+ case 135: // SO_SOUND_SOFT
+ _heSndFlags |= HE_SND_SOFT_SOUND;
break;
- case 136:
- _heSndFlags |= 32;
- pop();
+ case 136: // SO_SOUND_VOLUME
+ _heSndFlags |= HE_SND_VOL;
+ _heSndVol = pop();
break;
default:
- error("o100_startSound invalid case %d", subOp);
+ error("o100_soundOps invalid case %d", subOp);
}
}
@@ -1781,14 +1817,14 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 0:
+ case 0: // SO_INIT
_curMaxSpriteId = pop();
_curSpriteId = pop();
if (_curSpriteId > _curMaxSpriteId)
SWAP(_curSpriteId, _curMaxSpriteId);
break;
- case 2:
+ case 2: // SO_ANGLE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1799,7 +1835,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteAngle(spriteId, args[0]);
break;
- case 3:
+ case 3: // SO_ANIMATION
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1810,7 +1846,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagAutoAnim(spriteId, args[0]);
break;
- case 4:
+ case 4: // SO_ANIMATION_SPEED
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1821,7 +1857,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteAnimSpeed(spriteId, args[0]);
break;
- case 6:
+ case 6: // SO_AT
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1833,7 +1869,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePosition(spriteId, args[0], args[1]);
break;
- case 7:
+ case 7: // SO_AT_IMAGE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1844,7 +1880,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteSourceImage(spriteId, args[0]);
break;
- case 16:
+ case 16: // SO_CLASS
n = getStackList(args, ARRAYSIZE(args));
if (_curSpriteId != 0 && _curMaxSpriteId != 0 && n != 0) {
int *p = &args[n - 1];
@@ -1867,7 +1903,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
} while (--n);
}
break;
- case 32:
+ case 32: // SO_ERASE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1878,7 +1914,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagEraseType(spriteId, args[0]);
break;
- case 38:
+ case 38: // SO_GROUP
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1889,7 +1925,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteGroup(spriteId, args[0]);
break;
- case 40:
+ case 40: // SO_IMAGE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1900,7 +1936,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteImage(spriteId, args[0]);
break;
- case 48:
+ case 48: // SO_MASK
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1911,7 +1947,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteMaskImage(spriteId, args[0]);
break;
- case 49:
+ case 49: // SO_MOVE
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1923,10 +1959,10 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->moveSprite(spriteId, args[0], args[1]);
break;
- case 52:
+ case 52: // SO_NAME
copyScriptString(string, sizeof(string));
break;
- case 53:
+ case 53: // SO_NEW
if (_curSpriteId > _curMaxSpriteId)
break;
spriteId = _curSpriteId;
@@ -1936,7 +1972,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->resetSprite(spriteId);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1948,7 +1984,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteGeneralProperty(spriteId, args[0], args[1]);
break;
- case 57:
+ case 57: // SO_PALETTE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1959,7 +1995,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePalette(spriteId, args[0]);
break;
- case 59:
+ case 59: // SO_PRIORITY
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -1970,7 +2006,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpritePriority(spriteId, args[0]);
break;
- case 60:
+ case 60: // SO_PROPERTY
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -1997,13 +2033,14 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
_sprite->setSpriteFlagRemapPalette(spriteId, args[0]);
break;
default:
+ warning("Unknown sprite property %d for sprite %d", args[0], spriteId);
break;
}
break;
- case 61:
+ case 61: // SO_RESTART
_sprite->resetTables(true);
break;
- case 65:
+ case 65: // SO_SCALE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2014,7 +2051,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteScale(spriteId, args[0]);
break;
- case 70:
+ case 70: // SO_SHADOW
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2025,7 +2062,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteShadow(spriteId, args[0]);
break;
- case 73:
+ case 73: // SO_STATE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2036,7 +2073,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteImageState(spriteId, args[0]);
break;
- case 74:
+ case 74: // SO_STEP_DIST
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -2048,7 +2085,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteDist(spriteId, args[0], args[1]);
break;
- case 75:
+ case 75: // SO_STEP_DIST_X
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2061,7 +2098,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
_sprite->setSpriteDist(spriteId, args[0], tmp[1]);
}
break;
- case 76:
+ case 76: // SO_STEP_DIST_Y
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2074,7 +2111,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
_sprite->setSpriteDist(spriteId, tmp[0], args[0]);
}
break;
- case 82:
+ case 82: // SO_UPDATE
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2085,7 +2122,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteFlagUpdateType(spriteId, args[0]);
break;
- case 83:
+ case 83: // SO_VARIABLE
args[1] = pop();
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
@@ -2097,7 +2134,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
for (; spriteId <= _curMaxSpriteId; spriteId++)
_sprite->setSpriteUserValue(spriteId, args[0], args[1]);
break;
- case 88:
+ case 88: // SO_IMAGE_ZCLIP
args[0] = pop();
if (_curSpriteId > _curMaxSpriteId)
break;
@@ -2106,9 +2143,9 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
spriteId++;
for (; spriteId <= _curMaxSpriteId; spriteId++)
- _sprite->setSpriteField84(spriteId, args[0]);
+ _sprite->setSpriteZBuffer(spriteId, args[0]);
break;
- case 89:
+ case 89: // SO_NEVER_ZCLIP
if (_curSpriteId > _curMaxSpriteId)
break;
spriteId = _curSpriteId;
@@ -2116,7 +2153,7 @@ void ScummEngine_v100he::o100_setSpriteInfo() {
spriteId++;
for (; spriteId <= _curMaxSpriteId; spriteId++)
- _sprite->setSpriteField84(spriteId, 0);
+ _sprite->setSpriteZBuffer(spriteId, 0);
break;
default:
error("o100_setSpriteInfo: Unknown case %d", subOp);
@@ -2235,40 +2272,43 @@ void ScummEngine_v100he::o100_videoOps() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 0:
+ case 0: // SO_INIT
memset(_videoParams.filename, 0, sizeof(_videoParams.filename));
_videoParams.status = 0;
_videoParams.flags = 0;
- _videoParams.unk2 = pop();
+ _videoParams.number = pop();
_videoParams.wizResNum = 0;
+
+ if (_videoParams.number != 1 && _videoParams.number != -1)
+ warning("o100_videoOps: number: %d", _videoParams.number);
break;
- case 19:
+ case 19: // SO_CLOSE
_videoParams.status = 19;
break;
- case 40:
+ case 40: // SO_IMAGE
_videoParams.wizResNum = pop();
if (_videoParams.wizResNum)
_videoParams.flags |= 2;
break;
- case 47:
+ case 47: // SO_LOAD
copyScriptString(_videoParams.filename, sizeof(_videoParams.filename));
_videoParams.status = 47;
break;
- case 67:
+ case 67: // SO_SET_FLAGS
_videoParams.flags |= pop();
break;
- case 92:
- if (_videoParams.status == 47) {
+ case 92: // SO_END
+ if (_videoParams.status == 47) { // SO_LOAD
// Start video
if (_videoParams.flags == 0)
_videoParams.flags = 4;
- if (_videoParams.flags == 2) {
+ if (_videoParams.flags & 2) {
VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags, _videoParams.wizResNum);
} else {
VAR(119) = _moviePlay->load(convertFilePath(_videoParams.filename), _videoParams.flags);
}
- } else if (_videoParams.status == 19) {
+ } else if (_videoParams.status == 19) { // SO_CLOSE
// Stop video
_moviePlay->close();
}
@@ -2448,49 +2488,52 @@ void ScummEngine_v100he::o100_getSpriteGroupInfo() {
byte subOp = fetchScriptByte();
+ warning("o100_getSpriteGroupInfo, subop %d", subOp);
+
switch (subOp) {
- case 5:
+ case 5: // SO_ARRAY
spriteGroupId = pop();
if (spriteGroupId)
push(getGroupSpriteArray(spriteGroupId));
else
push(0);
break;
- case 40:
+ case 40: // SO_IMAGE
spriteGroupId = pop();
if (spriteGroupId)
push(_sprite->getGroupDstResNum(spriteGroupId));
else
push(0);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
// TODO: U32 related
pop();
pop();
push(0);
+ warning("STUB: o100_getSpriteGroupInfo, subop 54");
break;
- case 59:
+ case 59: // SO_PRIORITY
spriteGroupId = pop();
if (spriteGroupId)
push(_sprite->getGroupPriority(spriteGroupId));
else
push(0);
break;
- case 60:
+ case 60: // SO_PROPERTY
type = pop();
spriteGroupId = pop();
if (spriteGroupId) {
switch (type) {
- case 0:
+ case 0: // SPRGRPPROP_XMUL
push(_sprite->getGroupXMul(spriteGroupId));
break;
- case 1:
+ case 1: // SPRGRPPROP_XDIV
push(_sprite->getGroupXDiv(spriteGroupId));
break;
- case 2:
+ case 2: // SPRGRPPROP_YMUL
push(_sprite->getGroupYMul(spriteGroupId));
break;
- case 3:
+ case 3: // SPRGRPPROP_YDIV
push(_sprite->getGroupYDiv(spriteGroupId));
break;
default:
@@ -2500,7 +2543,7 @@ void ScummEngine_v100he::o100_getSpriteGroupInfo() {
push(0);
}
break;
- case 85:
+ case 85: // SO_XPOS
spriteGroupId = pop();
if (spriteGroupId) {
_sprite->getGroupPosition(spriteGroupId, tx, ty);
@@ -2509,7 +2552,7 @@ void ScummEngine_v100he::o100_getSpriteGroupInfo() {
push(0);
}
break;
- case 86:
+ case 86: // SO_YPOS
spriteGroupId = pop();
if (spriteGroupId) {
_sprite->getGroupPosition(spriteGroupId, tx, ty);
@@ -2532,62 +2575,62 @@ void ScummEngine_v100he::o100_getWizData() {
byte subOp = fetchScriptByte();
switch (subOp) {
- case 20:
+ case 20: // SO_COLOR
y = pop();
x = pop();
state = pop();
resId = pop();
push(_wiz->getWizPixelColor(resId, state, x, y));
break;
- case 26:
+ case 26: // SO_COUNT
resId = pop();
push(_wiz->getWizImageStates(resId));
break;
- case 33:
+ case 33: // SO_FIND
y = pop();
x = pop();
state = pop();
resId = pop();
push(_wiz->isWizPixelNonTransparent(resId, state, x, y, 0));
break;
- case 39:
+ case 39: // SO_HEIGHT
state = pop();
resId = pop();
_wiz->getWizImageDim(resId, state, w, h);
push(h);
break;
- case 54:
+ case 54: // SO_NEW_GENERAL_PROPERTY
type = pop();
state = pop();
resId = pop();
push(_wiz->getWizImageData(resId, state, type));
break;
- case 84:
+ case 84: // SO_WIDTH
state = pop();
resId = pop();
_wiz->getWizImageDim(resId, state, w, h);
push(w);
break;
- case 85:
+ case 85: // SO_XPOS
state = pop();
resId = pop();
_wiz->getWizImageSpot(resId, state, x, y);
push(x);
break;
- case 86:
+ case 86: // SO_YPOS
state = pop();
resId = pop();
_wiz->getWizImageSpot(resId, state, x, y);
push(y);
break;
- case 131:
+ case 131: // SO_FONT_START
pop();
copyScriptString(filename, sizeof(filename));
pop();
push(0);
debug(0, "o100_getWizData() case 111 unhandled");
break;
- case 132:
+ case 132: // SO_HISTOGRAM
h = pop();
w = pop();
y = pop();
diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp
index a911487738..0bdeb3211e 100644
--- a/engines/scumm/he/script_v70he.cpp
+++ b/engines/scumm/he/script_v70he.cpp
@@ -39,7 +39,7 @@ namespace Scumm {
void ScummEngine_v70he::setupOpcodes() {
ScummEngine_v60he::setupOpcodes();
- OPCODE(0x74, o70_startSound);
+ OPCODE(0x74, o70_soundOps);
OPCODE(0x84, o70_pickupObject);
OPCODE(0x8c, o70_getActorRoom);
OPCODE(0x9b, o70_resourceRoutines);
@@ -52,59 +52,60 @@ void ScummEngine_v70he::setupOpcodes() {
OPCODE(0xfa, o70_setSystemMessage);
}
-void ScummEngine_v70he::o70_startSound() {
+void ScummEngine_v70he::o70_soundOps() {
int var, value;
byte subOp = fetchScriptByte();
switch (subOp) {
- case 9:
- _heSndFlags |= 4;
+ case 9: // SO_SOUND_SOFT?
+ _heSndFlags |= HE_SND_SOFT_SOUND;
break;
- case 23:
+ case 23: // SO_VARIABLE
value = pop();
var = pop();
_heSndSoundId = pop();
((SoundHE *)_sound)->setSoundVar(_heSndSoundId, var, value);
break;
- case 25:
+ case 25: // SO_SOUND_VOLUME
value = pop();
_heSndSoundId = pop();
- _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8);
- case 56:
- _heSndFlags |= 16;
+ _sound->addSoundToQueue(_heSndSoundId, 0, 0, HE_SND_VOL, 0, 0, value);
break;
- case 164:
- _heSndFlags |= 2;
+ case 56: // SO_NOW
+ _heSndFlags |= HE_SND_QUICK_START;
+ break;
+ case 164: // SO_SOUND_ADD
+ _heSndFlags |= HE_SND_APPEND;
break;
case 222:
// WORKAROUND: For errors in room script 240 (room 4) of maze
break;
- case 224:
+ case 224: // SO_SOUND_FREQUENCY
_heSndSoundFreq = pop();
break;
- case 230:
+ case 230: // SO_SOUND_CHANNEL
_heSndChannel = pop();
break;
- case 231:
+ case 231: // SO_AT
_heSndOffset = pop();
break;
- case 232:
+ case 232: // SO_SOUND_START
_heSndSoundId = pop();
_heSndOffset = 0;
_heSndSoundFreq = 11025;
_heSndChannel = VAR(VAR_SOUND_CHANNEL);
break;
- case 245:
- _heSndFlags |= 1;
+ case 245: // SO_SOUND_LOOPING
+ _heSndFlags |= HE_SND_LOOP;
break;
- case 255:
- _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags);
+ case 255: // SO_END
+ _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags, _heSndSoundFreq);
_heSndFlags = 0;
break;
default:
- error("o70_startSound invalid case %d", subOp);
+ error("o70_soundOps invalid case %d", subOp);
}
}
diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp
index 31b4887d10..d32eb766cb 100644
--- a/engines/scumm/he/script_v72he.cpp
+++ b/engines/scumm/he/script_v72he.cpp
@@ -119,7 +119,7 @@ byte *ScummEngine_v72he::defineArray(int array, int type, int dim2start, int dim
id = findFreeArrayId();
- debug(9,"defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
+ debug(9, "defineArray (array %d, dim2start %d, dim2end %d dim1start %d dim1end %d", id, dim2start, dim2end, dim1start, dim1end);
if (array & 0x80000000) {
error("Can't define bit variable as array pointer");
@@ -699,13 +699,13 @@ void ScummEngine_v72he::o72_roomOps() {
setCurrentPalette(a);
break;
- case 220:
+ case 220: // SO_ROOM_COPY_PALETTE
a = pop();
b = pop();
copyPalColor(a, b);
break;
- case 221:
+ case 221: // SO_ROOM_SAVEGAME_BY_NAME
byte buffer[256];
copyScriptString((byte *)buffer, sizeof(buffer));
@@ -718,13 +718,13 @@ void ScummEngine_v72he::o72_roomOps() {
_saveTemporaryState = true;
break;
- case 234:
+ case 234: // SO_OBJECT_ORDER
b = pop();
a = pop();
swapObjects(a, b);
break;
- case 236:
+ case 236: // SO_ROOM_PALETTE_IN_ROOM
b = pop();
a = pop();
setRoomPalette(a, b);
@@ -752,43 +752,43 @@ void ScummEngine_v72he::o72_actorOps() {
return;
switch (subOp) {
- case 21: // HE 80+
+ case 21: // SO_CONDITION (HE 80+)
k = getStackList(args, ARRAYSIZE(args));
for (i = 0; i < k; ++i) {
a->setUserCondition(args[i] & 0x7F, args[i] & 0x80);
}
break;
- case 24: // HE 80+
+ case 24: // SO_TALK_CONDITION (HE 80+)
k = pop();
if (k == 0)
k = _rnd.getRandomNumberRng(1, 10);
a->_heNoTalkAnimation = 1;
a->setTalkCondition(k);
break;
- case 43: // HE 90+
+ case 43: // SO_PRIORITY (HE 90+)
a->_layer = pop();
a->_needRedraw = true;
break;
- case 64:
+ case 64: // SO_ACTOR_DEFAULT_CLIPPED
_actorClipOverride.bottom = pop();
_actorClipOverride.right = pop();
_actorClipOverride.top = pop();
_actorClipOverride.left = pop();
adjustRect(_actorClipOverride);
break;
- case 65: // HE 98+
+ case 65: // SO_AT (HE 98+)
j = pop();
i = pop();
a->putActor(i, j);
break;
- case 67: // HE 99+
+ case 67: // SO_CLIPPED (HE 99+)
a->_clipOverride.bottom = pop();
a->_clipOverride.right = pop();
a->_clipOverride.top = pop();
a->_clipOverride.left = pop();
adjustRect(a->_clipOverride);
break;
- case 68: // HE 90+
+ case 68: // // SO_ERASE (HE 90+)
k = pop();
a->setHEFlag(1, k);
break;
@@ -887,10 +887,10 @@ void ScummEngine_v72he::o72_actorOps() {
a->_talkPosY = pop();
a->_talkPosX = pop();
break;
- case 156: // HE 72+
+ case 156: // SO_CHARSET (HE 72+)
a->_charset = pop();
break;
- case 175: // HE 99+
+ case 175: // SO_ROOM_PALETTE (HE 99+)
a->_hePaletteNum = pop();
a->_needRedraw = true;
break;
@@ -907,15 +907,15 @@ void ScummEngine_v72he::o72_actorOps() {
case 217: // SO_ACTOR_NEW
a->initActor(2);
break;
- case 218:
+ case 218: // SO_BACKGROUND_ON
a->drawActorToBackBuf(a->getPos().x, a->getPos().y);
break;
- case 219:
+ case 219: // SO_BACKGROUND_OFF
a->_drawToBackBuf = false;
a->_needRedraw = true;
a->_needBgReset = true;
break;
- case 225:
+ case 225: // SO_TALKIE
{
copyScriptString(string, sizeof(string));
int slot = pop();
@@ -1077,7 +1077,7 @@ void ScummEngine_v72he::o72_arrayOps() {
memcpy(data, string, len);
break;
- case 126:
+ case 126: // SO_COMPLEX_ARRAY_ASSIGNMENT
len = getStackList(list, ARRAYSIZE(list));
dim1end = pop();
dim1start = pop();
@@ -1101,7 +1101,7 @@ void ScummEngine_v72he::o72_arrayOps() {
dim2start++;
}
break;
- case 127:
+ case 127: // SO_COMPLEX_ARRAY_COPY_OPERATION
{
int a2_dim1end = pop();
int a2_dim1start = pop();
@@ -1118,7 +1118,7 @@ void ScummEngine_v72he::o72_arrayOps() {
copyArray(array, a1_dim2start, a1_dim2end, a1_dim1start, a1_dim1end, array2, a2_dim2start, a2_dim2end, a2_dim1start, a2_dim1end);
}
break;
- case 128:
+ case 128: // SO_RANGE_ARRAY_ASSIGNMENT
b = pop();
c = pop();
dim1end = pop();
@@ -1149,7 +1149,7 @@ void ScummEngine_v72he::o72_arrayOps() {
dim2start++;
}
break;
- case 194:
+ case 194: // SO_FORMATTED_STRING
decodeScriptString(string);
len = resStrLen(string);
data = defineArray(array, kStringArray, 0, 0, 0, len);
diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp
index f65d2f6077..f63973e3f1 100644
--- a/engines/scumm/he/script_v90he.cpp
+++ b/engines/scumm/he/script_v90he.cpp
@@ -285,29 +285,29 @@ void ScummEngine_v90he::o90_wizImageOps() {
_wizParams.processMode = 13;
break;
case 142: // HE99+
- _wizParams.field_239D = pop();
- _wizParams.field_2399 = pop();
- _wizParams.field_23A5 = pop();
- _wizParams.field_23A1 = pop();
- copyScriptString(_wizParams.string2, sizeof(_wizParams.string2));
_wizParams.processMode = 15;
+ _wizParams.fontProperties.bgColor = pop();
+ _wizParams.fontProperties.fgColor = pop();
+ _wizParams.fontProperties.size = pop();
+ _wizParams.fontProperties.style = pop();
+ copyScriptString(_wizParams.fontProperties.fontName, sizeof(_wizParams.fontProperties.fontName));
break;
case 143: // HE99+
_wizParams.processMode = 16;
- _wizParams.field_23AD = pop();
- _wizParams.field_23A9 = pop();
- copyScriptString(_wizParams.string1, sizeof(_wizParams.string1));
+ _wizParams.fontProperties.yPos = pop();
+ _wizParams.fontProperties.xPos = pop();
+ copyScriptString(_wizParams.fontProperties.string, sizeof(_wizParams.fontProperties.string));
break;
case 189: // HE99+
_wizParams.processMode = 17;
- _wizParams.field_23CD = pop();
- _wizParams.field_23C9 = pop();
- _wizParams.field_23C5 = pop();
- _wizParams.field_23C1 = pop();
- _wizParams.field_23BD = pop();
- _wizParams.field_23B9 = pop();
- _wizParams.field_23B5 = pop();
- _wizParams.field_23B1 = pop();
+ _wizParams.ellipseProperties.color = pop();
+ _wizParams.ellipseProperties.lod = pop();
+ _wizParams.ellipseProperties.ky = pop();
+ _wizParams.ellipseProperties.kx = pop();
+ _wizParams.ellipseProperties.qy = pop();
+ _wizParams.ellipseProperties.qx = pop();
+ _wizParams.ellipseProperties.py = pop();
+ _wizParams.ellipseProperties.px = pop();
break;
case 196: // HE99+
_wizParams.processMode = 14;
@@ -1412,7 +1412,7 @@ void ScummEngine_v90he::o90_videoOps() {
memset(_videoParams.filename, 0, sizeof(_videoParams.filename));
_videoParams.status = 0;
_videoParams.flags = 0;
- _videoParams.unk2 = pop();
+ _videoParams.number = pop();
_videoParams.wizResNum = 0;
break;
case 14:
diff --git a/engines/scumm/he/sound_he.cpp b/engines/scumm/he/sound_he.cpp
index b806a9f3cc..9da3641064 100644
--- a/engines/scumm/he/sound_he.cpp
+++ b/engines/scumm/he/sound_he.cpp
@@ -34,14 +34,10 @@
#include "common/timer.h"
#include "common/util.h"
+#include "audio/audiostream.h"
#include "audio/decoders/adpcm.h"
-#include "audio/decoders/flac.h"
-#include "audio/mididrv.h"
#include "audio/mixer.h"
-#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
-#include "audio/decoders/voc.h"
-#include "audio/decoders/vorbis.h"
#include "audio/decoders/wave.h"
namespace Scumm {
@@ -55,37 +51,37 @@ SoundHE::SoundHE(ScummEngine *parent, Audio::Mixer *mixer)
_heMusicTracks(0) {
memset(_heChannel, 0, sizeof(_heChannel));
+ _heSoundChannels = new Audio::SoundHandle[8]();
}
SoundHE::~SoundHE() {
free(_heMusic);
+ delete[] _heSoundChannels;
}
-void SoundHE::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags) {
+void SoundHE::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
if (_vm->VAR_LAST_SOUND != 0xFF)
_vm->VAR(_vm->VAR_LAST_SOUND) = sound;
- if ((_vm->_game.heversion <= 99 && (heFlags & 16)) || (_vm->_game.heversion >= 100 && (heFlags & 8))) {
- playHESound(sound, heOffset, heChannel, heFlags);
- return;
+ if (heFlags & 8) {
+ playHESound(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
} else {
-
- Sound::addSoundToQueue(sound, heOffset, heChannel, heFlags);
+ Sound::addSoundToQueue(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
}
}
-void SoundHE::addSoundToQueue2(int sound, int heOffset, int heChannel, int heFlags) {
+void SoundHE::addSoundToQueue2(int sound, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
int i = _soundQue2Pos;
while (i--) {
if (_soundQue2[i].sound == sound && !(heFlags & 2))
return;
}
- Sound::addSoundToQueue2(sound, heOffset, heChannel, heFlags);
+ Sound::addSoundToQueue2(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
}
void SoundHE::processSoundQueues() {
- int snd, heOffset, heChannel, heFlags;
+ int snd, heOffset, heChannel, heFlags, heFreq, hePan, heVol;
if (_vm->_game.heversion >= 72) {
for (int i = 0; i <_soundQue2Pos; i++) {
@@ -93,8 +89,11 @@ void SoundHE::processSoundQueues() {
heOffset = _soundQue2[i].offset;
heChannel = _soundQue2[i].channel;
heFlags = _soundQue2[i].flags;
+ heFreq = _soundQue2[_soundQue2Pos].freq;
+ hePan = _soundQue2[_soundQue2Pos].pan;
+ heVol = _soundQue2[_soundQue2Pos].vol;
if (snd)
- playHESound(snd, heOffset, heChannel, heFlags);
+ playHESound(snd, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
}
_soundQue2Pos = 0;
} else {
@@ -104,8 +103,11 @@ void SoundHE::processSoundQueues() {
heOffset = _soundQue2[_soundQue2Pos].offset;
heChannel = _soundQue2[_soundQue2Pos].channel;
heFlags = _soundQue2[_soundQue2Pos].flags;
+ heFreq = _soundQue2[_soundQue2Pos].freq;
+ hePan = _soundQue2[_soundQue2Pos].pan;
+ heVol = _soundQue2[_soundQue2Pos].vol;
if (snd)
- playHESound(snd, heOffset, heChannel, heFlags);
+ playHESound(snd, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
}
}
@@ -474,6 +476,10 @@ void SoundHE::processSoundOpcodes(int sound, byte *codePtr, int *soundVars) {
if (arg == 2) {
val = getSoundVar(sound, val);
}
+ if (!val) {
+ val = 1; // Safeguard for division by zero
+ warning("Incorrect value 0 for processSoundOpcodes() kludge DIV");
+ }
val = getSoundVar(sound, var) / val;
setSoundVar(sound, var, val);
break;
@@ -525,7 +531,7 @@ byte *findSoundTag(uint32 tag, byte *ptr) {
return NULL;
}
-void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags) {
+void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
Audio::RewindableAudioStream *stream = 0;
byte *ptr, *spoolPtr;
int size = -1;
diff --git a/engines/scumm/he/sound_he.h b/engines/scumm/he/sound_he.h
index 323858a7c9..d5a2817a0f 100644
--- a/engines/scumm/he/sound_he.h
+++ b/engines/scumm/he/sound_he.h
@@ -44,7 +44,7 @@ protected:
HEMusic *_heMusic;
int16 _heMusicTracks;
- Audio::SoundHandle _heSoundChannels[8];
+ Audio::SoundHandle *_heSoundChannels;
public: // Used by createSound()
struct {
@@ -61,8 +61,8 @@ public:
SoundHE(ScummEngine *parent, Audio::Mixer *mixer);
~SoundHE();
- virtual void addSoundToQueue(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0);
- virtual void addSoundToQueue2(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0);
+ virtual void addSoundToQueue(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0, int heFreq = 0, int hePan = 0, int heVol = 0);
+ virtual void addSoundToQueue2(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0, int heFreq = 0, int hePan = 0, int heVol = 0);
virtual int isSoundRunning(int sound) const;
virtual void stopSound(int sound);
@@ -75,7 +75,7 @@ public:
int getSoundPos(int sound);
int getSoundVar(int sound, int var);
void setSoundVar(int sound, int var, int val);
- void playHESound(int soundID, int heOffset, int heChannel, int heFlags);
+ void playHESound(int soundID, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol);
void processSoundCode();
void processSoundOpcodes(int sound, byte *codePtr, int *soundVars);
void setOverrideFreq(int freq);
diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp
index 245a986531..e3f04dfcf0 100644
--- a/engines/scumm/he/sprite_he.cpp
+++ b/engines/scumm/he/sprite_he.cpp
@@ -386,7 +386,7 @@ int Sprite::getSpriteGeneralProperty(int spriteId, int type) {
case 0x7B:
return _spriteTable[spriteId].imgFlags;
case 0x7D:
- return _spriteTable[spriteId].field_90;
+ return _spriteTable[spriteId].conditionBits;
case 0x7E:
return _spriteTable[spriteId].animProgress;
default:
@@ -739,26 +739,24 @@ void Sprite::setSpriteResetClass(int spriteId) {
_spriteTable[spriteId].classFlags = 0;
}
-void Sprite::setSpriteField84(int spriteId, int value) {
+void Sprite::setSpriteZBuffer(int spriteId, int value) {
assertRange(1, spriteId, _varNumSprites, "sprite");
- _spriteTable[spriteId].field_84 = value;
+ _spriteTable[spriteId].zbufferImage = value;
}
void Sprite::setSpriteGeneralProperty(int spriteId, int type, int value) {
- debug(0, "setSpriteGeneralProperty: spriteId %d type 0x%x", spriteId, type);
+ debug(6, "setSpriteGeneralProperty: spriteId %d type 0x%x value 0x%x", spriteId, type, value);
assertRange(1, spriteId, _varNumSprites, "sprite");
int32 delay;
- // XXX U32 related check
-
switch (type) {
case 0x7B:
_spriteTable[spriteId].imgFlags = value;
_spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw;
break;
case 0x7D:
- _spriteTable[spriteId].field_90 = value;
+ _spriteTable[spriteId].conditionBits = value;
_spriteTable[spriteId].flags |= kSFChanged | kSFNeedRedraw;
break;
case 0x7E:
@@ -797,9 +795,9 @@ void Sprite::resetSprite(int spriteId) {
_spriteTable[spriteId].sourceImage = 0;
_spriteTable[spriteId].maskImage = 0;
_spriteTable[spriteId].priority = 0;
- _spriteTable[spriteId].field_84 = 0;
+ _spriteTable[spriteId].zbufferImage = 0;
_spriteTable[spriteId].imgFlags = 0;
- _spriteTable[spriteId].field_90 = 0;
+ _spriteTable[spriteId].conditionBits = 0;
if (_vm->_game.heversion >= 100) {
_spriteTable[spriteId].flags &= ~kSFMarkDirty;
@@ -816,7 +814,7 @@ void Sprite::setSpriteImage(int spriteId, int imageNum) {
origResWizStates = _spriteTable[spriteId].imageStateCount;
_spriteTable[spriteId].image = imageNum;
- _spriteTable[spriteId].field_74 = 0;
+ _spriteTable[spriteId].animIndex = 0;
_spriteTable[spriteId].imageState = 0;
if (_spriteTable[spriteId].image) {
@@ -1292,7 +1290,7 @@ void Sprite::processImages(bool arg) {
wiz.spriteId = spi->id;
wiz.spriteGroup = spi->group;
- wiz.field_23EA = spi->field_90;
+ wiz.conditionBits = spi->conditionBits;
spi->curImageState = wiz.img.state = imageState;
spi->curImage = wiz.img.resNum = image;
wiz.processFlags = kWPFNewState | kWPFSetPos;
@@ -1339,9 +1337,9 @@ void Sprite::processImages(bool arg) {
}
if (spr_flags & kSFRemapPalette)
wiz.img.flags |= kWIFRemapPalette;
- if (spi->field_84) {
+ if (spi->zbufferImage) {
wiz.processFlags |= 0x200000;
- wiz.img.field_390 = spi->field_84;
+ wiz.img.zbuffer = spi->zbufferImage;
wiz.img.zorder = spi->priority;
}
if (spi->sourceImage) {
@@ -1419,14 +1417,14 @@ void Sprite::saveOrLoadSpriteData(Serializer *s) {
MKLINE(SpriteInfo, curAngle, sleInt32, VER(48)),
MKLINE(SpriteInfo, curScale, sleInt32, VER(48)),
MKLINE(SpriteInfo, curImgFlags, sleInt32, VER(48)),
- MKLINE(SpriteInfo, field_74, sleInt32, VER(48)),
+ MKLINE(SpriteInfo, animIndex, sleInt32, VER(48)),
MKLINE(SpriteInfo, animSpeed, sleInt32, VER(48)),
MKLINE(SpriteInfo, sourceImage, sleInt32, VER(48)),
MKLINE(SpriteInfo, maskImage, sleInt32, VER(48)),
- MKLINE(SpriteInfo, field_84, sleInt32, VER(48)),
+ MKLINE(SpriteInfo, zbufferImage, sleInt32, VER(48)),
MKLINE(SpriteInfo, classFlags, sleInt32, VER(48)),
MKLINE(SpriteInfo, imgFlags, sleInt32, VER(48)),
- MKLINE(SpriteInfo, field_90, sleInt32, VER(48)),
+ MKLINE(SpriteInfo, conditionBits, sleInt32, VER(48)),
MKEND()
};
diff --git a/engines/scumm/he/sprite_he.h b/engines/scumm/he/sprite_he.h
index e31ccbf790..3ea6bb9f84 100644
--- a/engines/scumm/he/sprite_he.h
+++ b/engines/scumm/he/sprite_he.h
@@ -72,14 +72,14 @@ struct SpriteInfo {
int32 curAngle;
int32 curScale;
int32 curImgFlags;
- int32 field_74;
+ int32 animIndex;
int32 animSpeed;
int32 sourceImage;
int32 maskImage;
- int32 field_84;
+ int32 zbufferImage;
int32 classFlags;
int32 imgFlags;
- int32 field_90;
+ int32 conditionBits;
};
struct SpriteGroup {
@@ -182,7 +182,7 @@ public:
void setSpriteAnimSpeed(int spriteId, int value);
void setSpriteSetClass(int spriteId, int classId, int toggle);
void setSpriteResetClass(int spriteId);
- void setSpriteField84(int spriteId, int value);
+ void setSpriteZBuffer(int spriteId, int value);
void setSpriteGeneralProperty(int spriteId, int type, int value);
void moveGroupMembers(int spriteGroupId, int value1, int value2);
diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp
index 9a59609651..9339318d19 100644
--- a/engines/scumm/he/wiz_he.cpp
+++ b/engines/scumm/he/wiz_he.cpp
@@ -31,6 +31,7 @@
#include "scumm/scumm.h"
#include "scumm/util.h"
#include "scumm/he/wiz_he.h"
+#include "scumm/he/moonbase/moonbase.h"
namespace Scumm {
@@ -976,7 +977,7 @@ void Wiz::decompressRawWizImage(uint8 *dst, int dstPitch, int dstType, const uin
}
}
-int Wiz::isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth) {
+int Wiz::isPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth) {
if (x < 0 || x >= w || y < 0 || y >= h) {
return 0;
}
@@ -1422,19 +1423,19 @@ void Wiz::displayWizImage(WizImage *pwi) {
wi->state = pwi->state;
wi->flags = pwi->flags;
wi->shadow = 0;
- wi->field_390 = 0;
+ wi->zbuffer = 0;
wi->palette = 0;
++_imagesNum;
} else if (pwi->flags & kWIFIsPolygon) {
drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, 0, 0, 0);
} else {
const Common::Rect *r = NULL;
- drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, _vm->getHEPaletteSlot(0));
+ drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, 0, 0, 0, r, pwi->flags, 0, _vm->getHEPaletteSlot(0), 0);
}
}
-uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr) {
- debug(3, "drawWizImage(resNum %d, state %d maskNum %d maskState %d x1 %d y1 %d flags 0x%X zorder %d shadow %d field_390 %d dstResNum %d)", resNum, state, maskNum, maskState, x1, y1, flags, zorder, shadow, field_390, dstResNum);
+uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int zbuffer, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr, uint32 conditionBits) {
+ debug(7, "drawWizImage(resNum %d, state %d maskNum %d maskState %d x1 %d y1 %d flags 0x%X zorder %d shadow %d zbuffer %d dstResNum %d conditionBits: 0x%x)", resNum, state, maskNum, maskState, x1, y1, flags, zorder, shadow, zbuffer, dstResNum, conditionBits);
uint8 *dataPtr;
uint8 *dst = NULL;
@@ -1454,10 +1455,7 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
uint32 comp = READ_LE_UINT32(wizh + 0x0);
uint32 width = READ_LE_UINT32(wizh + 0x4);
uint32 height = READ_LE_UINT32(wizh + 0x8);
- debug(3, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height);
-
- uint8 *wizd = _vm->findWrappedBlock(MKTAG('W','I','Z','D'), dataPtr, state, 0);
- assert(wizd);
+ debug(7, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height);
uint8 *mask = NULL;
if (maskNum) {
@@ -1574,58 +1572,258 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
transColor = (trns == NULL) ? _vm->VAR(_vm->VAR_WIZ_TCOLOR) : -1;
}
+ if (_vm->_game.id == GID_MOONBASE &&
+ ((ScummEngine_v100he *)_vm)->_moonbase->isFOW(resNum, state, conditionBits)) {
+ ((ScummEngine_v100he *)_vm)->_moonbase->renderFOW(dst, dstPitch, dstType, cw, ch, flags);
+ x1 = 0;
+ y1 = 0;
+ width = rScreen.width();
+ height = rScreen.height();
+ } else {
+ drawWizImageEx(dst, dataPtr, mask, dstPitch, dstType, cw, ch, x1, y1, width, height,
+ state, &rScreen, flags, palPtr, transColor, _vm->_bytesPerPixel, xmapPtr, conditionBits);
+ }
+
+ if (!(flags & kWIFBlitToMemBuffer) && dstResNum == 0) {
+ Common::Rect rImage(x1, y1, x1 + width, y1 + height);
+ if (rImage.intersects(rScreen)) {
+ rImage.clip(rScreen);
+ if (!(flags & kWIFBlitToFrontVideoBuffer) && (flags & (kWIFBlitToFrontVideoBuffer | kWIFMarkBufferDirty))) {
+ ++rImage.bottom;
+ _vm->markRectAsDirty(kMainVirtScreen, rImage);
+ } else {
+ _vm->restoreBackgroundHE(rImage);
+ }
+ }
+ }
+
+ return dst;
+}
+
+void Wiz::drawWizImageEx(uint8 *dst, uint8 *dataPtr, uint8 *maskPtr, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *rect,
+ int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits) {
+ uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), dataPtr, state, 0);
+ assert(wizh);
+ uint32 comp = READ_LE_UINT32(wizh + 0x0);
+ uint32 width = READ_LE_UINT32(wizh + 0x4);
+ uint32 height = READ_LE_UINT32(wizh + 0x8);
+ debug(7, "wiz_header.comp = %d wiz_header.w = %d wiz_header.h = %d", comp, width, height);
+
+ uint8 *wizd = _vm->findWrappedBlock(MKTAG('W','I','Z','D'), dataPtr, state, 0);
+ assert(wizd);
+
switch (comp) {
case 0:
- copyRawWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, transColor, _vm->_bytesPerPixel);
+ copyRawWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, palPtr, transColor, bitDepth);
break;
case 1:
- if (flags & 0x80) {
+ if (flags & kWIFZPlaneOn) {
dst = _vm->getMaskBuffer(0, 0, 1);
dstPitch /= _vm->_bytesPerPixel;
- copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 2);
- } else if (flags & 0x100) {
+ copyWizImageWithMask(dst, wizd, dstPitch, dstw, dsth, srcx, srcy, srcw, srch, rect, 0, 2);
+ } else if (flags & kWIFZPlaneOff) {
dst = _vm->getMaskBuffer(0, 0, 1);
dstPitch /= _vm->_bytesPerPixel;
- copyWizImageWithMask(dst, wizd, dstPitch, cw, ch, x1, y1, width, height, &rScreen, 0, 1);
+ copyWizImageWithMask(dst, wizd, dstPitch, dstw, dsth, srcx, srcy, srcw, srch, rect, 0, 1);
} else {
- copyWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr, xmapPtr, _vm->_bytesPerPixel);
+ copyWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, palPtr, xmapPtr, bitDepth);
}
break;
#ifdef USE_RGB_COLOR
case 2:
- if (maskNum) {
- copyMaskWizImage(dst, wizd, mask, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, palPtr);
+ if (maskPtr) {
+ copyMaskWizImage(dst, wizd, maskPtr, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, palPtr);
} else {
- copyRaw16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, transColor);
+ copyRaw16BitWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, transColor);
}
break;
case 4:
- // TODO: Unknown image type
+ copyCompositeWizImage(dst, dataPtr, wizd, maskPtr, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, state, rect, flags, palPtr, transColor, bitDepth, xmapPtr, conditionBits);
break;
case 5:
- copy16BitWizImage(dst, wizd, dstPitch, dstType, cw, ch, x1, y1, width, height, &rScreen, flags, xmapPtr);
+ copy16BitWizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, srcw, srch, rect, flags, xmapPtr);
+ break;
+ case 9:
+ copy555WizImage(dst, wizd, dstPitch, dstType, dstw, dsth, srcx, srcy, rect, conditionBits);
break;
#endif
default:
- error("drawWizImage: Unhandled wiz compression type %d", comp);
+ error("drawWizImageEx: Unhandled wiz compression type %d", comp);
}
+}
- if (!(flags & kWIFBlitToMemBuffer) && dstResNum == 0) {
- Common::Rect rImage(x1, y1, x1 + width, y1 + height);
- if (rImage.intersects(rScreen)) {
- rImage.clip(rScreen);
- if (!(flags & kWIFBlitToFrontVideoBuffer) && (flags & (kWIFBlitToFrontVideoBuffer | kWIFMarkBufferDirty))) {
- ++rImage.bottom;
- _vm->markRectAsDirty(kMainVirtScreen, rImage);
- } else {
- _vm->restoreBackgroundHE(rImage);
+#ifdef USE_RGB_COLOR
+
+void Wiz::copyCompositeWizImage(uint8 *dst, uint8 *wizPtr, uint8 *compositeInfoBlockPtr, uint8 *maskPtr, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *clipBox,
+ int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits) {
+
+ uint8 *nestedBlockHeader = _vm->heFindResource(MKTAG('N','E','S','T'), wizPtr);
+ assert(nestedBlockHeader);
+
+ uint8 *nestedWizHeader = _vm->heFindResource(MKTAG('M','U','L','T'), nestedBlockHeader);
+ assert(nestedWizHeader);
+
+ uint16 layerCount = READ_LE_UINT16(compositeInfoBlockPtr);
+ compositeInfoBlockPtr += 2;
+
+ uint16 defaultSubConditionBits = (conditionBits & kWMSBReservedBits);
+
+ conditionBits &= ~kWMSBReservedBits;
+
+ for (uint layerCounter = 0; layerCounter < layerCount; layerCounter++) {
+ int cmdSize = READ_LE_UINT16(compositeInfoBlockPtr);
+ uint8 *cmdPtr = compositeInfoBlockPtr + 2;
+
+ compositeInfoBlockPtr += (cmdSize + 2);
+ uint32 layerCmdDataBits = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+
+ uint32 subConditionBits;
+
+ if (layerCmdDataBits & kWCFConditionBits) {
+ uint32 layerConditionBits = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+
+ subConditionBits = (layerConditionBits & kWMSBReservedBits);
+ layerConditionBits &= ~kWMSBReservedBits;
+
+ if (subConditionBits == 0)
+ subConditionBits = defaultSubConditionBits;
+
+ uint32 conditionType = (layerConditionBits & kWSPCCTBits);
+ layerConditionBits &= ~kWSPCCTBits;
+
+ switch (conditionType) {
+ case kWSPCCTAnd:
+ if (layerConditionBits != (layerConditionBits & conditionBits))
+ continue;
+ break;
+
+ case kWSPCCTNot:
+ if (layerConditionBits & conditionBits)
+ continue;
+ break;
+
+ case kWSPCCTOr:
+ default:
+ if (!(layerConditionBits & conditionBits))
+ continue;
+ break;
}
+ } else {
+ subConditionBits = defaultSubConditionBits;
+ }
+
+ uint16 subState;
+ if (layerCmdDataBits & kWCFSubState) {
+ subState = READ_LE_UINT16(cmdPtr);
+ cmdPtr += 2;
+ } else {
+ subState = 0;
}
+
+ int16 xPos;
+ if (layerCmdDataBits & kWCFXDelta) {
+ xPos = (int16)READ_LE_UINT16(cmdPtr);
+ cmdPtr += 2;
+ } else {
+ xPos = 0;
+ }
+
+ int16 yPos;
+ if (layerCmdDataBits & kWCFYDelta) {
+ yPos = (int16)READ_LE_UINT16(cmdPtr);
+ cmdPtr += 2;
+ } else {
+ yPos = 0;
+ }
+
+ uint32 drawFlags;
+ if (layerCmdDataBits & kWCFDrawFlags) {
+ drawFlags = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+ } else {
+ drawFlags = flags;
+ }
+
+ uint srcw1 = 0, srch1 = 0;
+ if (drawFlags & (kWIFFlipX | kWIFFlipY)) {
+ uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), wizPtr, subState, 0);
+ assert(wizh);
+ srcw1 = READ_LE_UINT32(wizh + 0x4);
+ srch1 = READ_LE_UINT32(wizh + 0x8);
+ }
+
+ if (drawFlags & kWIFFlipX)
+ xPos = (srcw - (xPos + srcw1));
+
+ if (drawFlags & kWIFFlipY)
+ yPos = (srch - (yPos + srch1));
+
+ if (layerCmdDataBits & kWCFSubConditionBits) {
+ subConditionBits = READ_LE_UINT32(cmdPtr);
+ cmdPtr += 4;
+ }
+
+ drawWizImageEx(dst, nestedWizHeader, maskPtr, dstPitch, dstType, dstw, dsth, srcx + xPos, srcy + yPos, srcw, srch,
+ subState, clipBox, drawFlags, palPtr, transColor, bitDepth, xmapPtr, subConditionBits);
}
+}
- return dst;
+void Wiz::copy555WizImage(uint8 *dst, uint8 *wizd, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, const Common::Rect *clipBox, uint32 conditionBits) {
+
+ int rawROP = conditionBits & kWMSBRopMask;
+ int paramROP = (conditionBits & kWMSBReservedBits) >> kWMSBRopParamRShift;
+
+ switch (rawROP) {
+ default:
+ case 1:
+ rawROP = 1;
+ // MMX_PREMUL_ALPHA_COPY
+ break;
+
+ case 2:
+ //warning("T14: MMX_ADDITIVE");
+ break;
+
+ case 3:
+ warning("T14: MMX_SUBTRACTIVE");
+ break;
+
+ case 4:
+ warning("T14: MMX_CONSTANT_ALPHA");
+ break;
+
+ case 5:
+ //warning("T14: MMX_CHEAP_50_50");
+ break;
+
+ case 6:
+ warning("T14: COPY");
+ break;
+
+ case 7:
+ warning("T14: CHEAP_50_50");
+ break;
+ }
+
+
+ uint32 compID = READ_LE_UINT32(wizd);
+
+ if (compID == 0x12340102) {
+ ((ScummEngine_v100he *)_vm)->_moonbase->blitT14WizImage(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, rawROP, paramROP);
+ } else if (compID == 0x12340802) {
+ ((ScummEngine_v100he *)_vm)->_moonbase->blitDistortion(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, 0);
+ } else if (compID == 0x12340902) {
+ error("Unsupported Distortion");
+ }
}
+#endif
+
struct PolygonDrawData {
struct PolygonArea {
int32 xmin;
@@ -1747,7 +1945,7 @@ void Wiz::captureWizPolygon(int resNum, int maskNum, int maskState, int id1, int
assert(maskNum);
const Common::Rect *r = NULL;
- const uint8 *src = drawWizImage(maskNum, maskState, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0);
+ const uint8 *src = drawWizImage(maskNum, maskState, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, 0, 0);
getWizImageDim(maskNum, maskState, srcw, srch);
dstw = wp->bound.width();
@@ -1815,7 +2013,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int
debug(0, "drawWizPolygonTransform() unhandled flag 0x800000");
}
- srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, flags, 0, _vm->getHEPaletteSlot(palette));
+ srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, flags, 0, _vm->getHEPaletteSlot(palette), 0);
} else {
assert(_vm->_bytesPerPixel == 1);
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
@@ -1826,7 +2024,7 @@ void Wiz::drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int
}
} else {
if (getWizImageData(resNum, state, 0) != 0) {
- srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette));
+ srcWizBuf = drawWizImage(resNum, state, 0, 0, 0, 0, 0, shadow, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette), 0);
} else {
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
assert(dataPtr);
@@ -2001,7 +2199,7 @@ void Wiz::flushWizBuffer() {
drawWizPolygon(pwi->resNum, pwi->state, pwi->x1, pwi->flags, pwi->shadow, 0, pwi->palette);
} else {
const Common::Rect *r = NULL;
- drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->field_390, r, pwi->flags, 0, _vm->getHEPaletteSlot(pwi->palette));
+ drawWizImage(pwi->resNum, pwi->state, 0, 0, pwi->x1, pwi->y1, pwi->zorder, pwi->shadow, pwi->zbuffer, r, pwi->flags, 0, _vm->getHEPaletteSlot(pwi->palette), 0);
}
}
_imagesNum = 0;
@@ -2023,7 +2221,7 @@ void Wiz::loadWizCursor(int resId, int palette) {
const Common::Rect *r = NULL;
_cursorImage = true;
- uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette));
+ uint8 *cursor = drawWizImage(resId, 0, 0, 0, 0, 0, 0, 0, 0, r, kWIFBlitToMemBuffer, 0, _vm->getHEPaletteSlot(palette), 0);
_cursorImage = false;
int32 cw, ch;
@@ -2073,10 +2271,10 @@ void Wiz::displayWizComplexImage(const WizParameters *params) {
if (params->processFlags & kWPFShadow) {
shadow = params->img.shadow;
}
- int field_390 = 0;
- if (params->processFlags & 0x200000) {
- field_390 = params->img.field_390;
- debug(0, "displayWizComplexImage() unhandled flag 0x200000");
+ int zbuffer = 0;
+ if (params->processFlags & kWPFZBuffer) {
+ zbuffer = params->img.zbuffer;
+ debug(0, "displayWizComplexImage() unhandled flag kWPFZBuffer");
}
const Common::Rect *r = NULL;
if (params->processFlags & kWPFClipBox) {
@@ -2104,19 +2302,19 @@ void Wiz::displayWizComplexImage(const WizParameters *params) {
pwi->state = state;
pwi->flags = flags;
pwi->shadow = shadow;
- pwi->field_390 = field_390;
+ pwi->zbuffer = zbuffer;
pwi->palette = palette;
++_imagesNum;
} else {
if (sourceImage != 0) {
- drawWizImage(params->sourceImage, 0, params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette));
+ drawWizImage(params->sourceImage, 0, params->img.resNum, state, po_x, po_y, params->img.zorder, shadow, zbuffer, r, flags, dstResNum, _vm->getHEPaletteSlot(palette), 0);
} else if (params->processFlags & (kWPFScaled | kWPFRotate)) {
drawWizComplexPolygon(params->img.resNum, state, po_x, po_y, shadow, rotationAngle, scale, r, flags, dstResNum, palette);
} else {
if (flags & kWIFIsPolygon) {
drawWizPolygon(params->img.resNum, state, po_x, flags, shadow, dstResNum, palette);
} else {
- drawWizImage(params->img.resNum, state, 0, 0, po_x, po_y, params->img.zorder, shadow, field_390, r, flags, dstResNum, _vm->getHEPaletteSlot(palette));
+ drawWizImage(params->img.resNum, state, 0, 0, po_x, po_y, params->img.zorder, shadow, zbuffer, r, flags, dstResNum, _vm->getHEPaletteSlot(palette), params->conditionBits);
}
}
}
@@ -2501,6 +2699,10 @@ void Wiz::processWizImage(const WizParameters *params) {
void Wiz::getWizImageDim(int resNum, int state, int32 &w, int32 &h) {
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
assert(dataPtr);
+ getWizImageDim(dataPtr, state, w, h);
+}
+
+void Wiz::getWizImageDim(uint8 *dataPtr, int state, int32 &w, int32 &h) {
uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), dataPtr, state, 0);
assert(wizh);
w = READ_LE_UINT32(wizh + 0x4);
@@ -2510,6 +2712,10 @@ void Wiz::getWizImageDim(int resNum, int state, int32 &w, int32 &h) {
void Wiz::getWizImageSpot(int resId, int state, int32 &x, int32 &y) {
uint8 *dataPtr = _vm->getResourceAddress(rtImage, resId);
assert(dataPtr);
+ getWizImageSpot(dataPtr, state, x, y);
+}
+
+void Wiz::getWizImageSpot(uint8 *dataPtr, int state, int32 &x, int32 &y) {
uint8 *spotPtr = _vm->findWrappedBlock(MKTAG('S','P','O','T'), dataPtr, state, 0);
if (spotPtr) {
x = READ_LE_UINT32(spotPtr + 0);
@@ -2547,6 +2753,11 @@ int Wiz::getWizImageData(int resNum, int state, int type) {
int Wiz::getWizImageStates(int resNum) {
const uint8 *dataPtr = _vm->getResourceAddress(rtImage, resNum);
assert(dataPtr);
+
+ return getWizImageStates(dataPtr);
+}
+
+int Wiz::getWizImageStates(const uint8 *dataPtr) {
if (READ_BE_UINT32(dataPtr) == MKTAG('M','U','L','T')) {
const byte *offs, *wrap;
@@ -2565,14 +2776,27 @@ int Wiz::getWizImageStates(int resNum) {
}
int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags) {
- int ret = 0;
uint8 *data = _vm->getResourceAddress(rtImage, resNum);
assert(data);
+
+ return isWizPixelNonTransparent(data, state, x, y, flags);
+}
+
+int Wiz::isWizPixelNonTransparent(uint8 *data, int state, int x, int y, int flags) {
+ int ret = 0;
uint8 *wizh = _vm->findWrappedBlock(MKTAG('W','I','Z','H'), data, state, 0);
assert(wizh);
int c = READ_LE_UINT32(wizh + 0x0);
int w = READ_LE_UINT32(wizh + 0x4);
int h = READ_LE_UINT32(wizh + 0x8);
+
+ if (_vm->_game.id == GID_MOONBASE) {
+ uint16 color = 0xffff;
+ drawWizImageEx((byte *)&color, data, 0, 2, kDstMemory, 1, 1, -x, -y, w, h, state, 0, 0, 0, 0, 2, 0, 0);
+
+ return color != 0xffff;
+ }
+
uint8 *wizd = _vm->findWrappedBlock(MKTAG('W','I','Z','D'), data, state, 0);
assert(wizd);
if (x >= 0 && x < w && y >= 0 && y < h) {
@@ -2591,19 +2815,20 @@ int Wiz::isWizPixelNonTransparent(int resNum, int state, int x, int y, int flags
}
break;
case 1:
- ret = isWizPixelNonTransparent(wizd, x, y, w, h, 1);
+ ret = isPixelNonTransparent(wizd, x, y, w, h, 1);
break;
#ifdef USE_RGB_COLOR
case 2:
ret = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR)) != _vm->VAR(_vm->VAR_WIZ_TCOLOR) ? 1 : 0;
break;
- case 4:
- // TODO: Unknown image type
- ret = 1;
- debug(0, "isWizPixelNonTransparent: Unhandled wiz compression type %d", c);
+ case 4: {
+ uint16 color = 0xffff;
+ copyCompositeWizImage((byte *)&color, data, wizd, 0, 2, kDstMemory, 1, 1, -x, -y, w, h, state, 0, 0, 0, 0, 2, 0, 0);
+ ret = color != 0xffff;
break;
+ }
case 5:
- ret = isWizPixelNonTransparent(wizd, x, y, w, h, 2);
+ ret = isPixelNonTransparent(wizd, x, y, w, h, 2);
break;
#endif
default:
@@ -2623,6 +2848,13 @@ uint16 Wiz::getWizPixelColor(int resNum, int state, int x, int y) {
int c = READ_LE_UINT32(wizh + 0x0);
int w = READ_LE_UINT32(wizh + 0x4);
int h = READ_LE_UINT32(wizh + 0x8);
+
+ if (_vm->_game.id == GID_MOONBASE) {
+ drawWizImageEx((byte *)&color, data, 0, 2, kDstMemory, 1, 1, -x, -y, w, h, state, 0, 0, 0, 0, 2, 0, 0);
+
+ return color;
+ }
+
uint8 *wizd = _vm->findWrappedBlock(MKTAG('W','I','Z','D'), data, state, 0);
assert(wizd);
switch (c) {
@@ -2641,8 +2873,7 @@ uint16 Wiz::getWizPixelColor(int resNum, int state, int x, int y) {
color = getRawWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR));
break;
case 4:
- // TODO: Unknown image type
- debug(0, "getWizPixelColor: Unhandled wiz compression type %d", c);
+ copyCompositeWizImage((byte *)&color, data, wizd, 0, 2, kDstMemory, 1, 1, -x, -y, w, h, state, 0, 0, 0, 0, 2, 0, 0);
break;
case 5:
color = getWizPixelColor(wizd, x, y, w, h, 2, _vm->VAR(_vm->VAR_WIZ_TCOLOR));
diff --git a/engines/scumm/he/wiz_he.h b/engines/scumm/he/wiz_he.h
index 8db438a074..692ad76db5 100644
--- a/engines/scumm/he/wiz_he.h
+++ b/engines/scumm/he/wiz_he.h
@@ -43,10 +43,32 @@ struct WizImage {
int state;
int flags;
int shadow;
- int field_390;
+ int zbuffer;
int palette;
};
+struct FontProperties {
+ byte string[4096];
+ byte fontName[4096];
+ int fgColor;
+ int bgColor;
+ int style;
+ int size;
+ int xPos;
+ int yPos;
+};
+
+struct EllipseProperties {
+ int px;
+ int py;
+ int qx;
+ int qy;
+ int kx;
+ int ky;
+ int lod;
+ int color;
+};
+
struct WizParameters {
int field_0;
byte filename[260];
@@ -77,27 +99,13 @@ struct WizParameters {
int remapNum;
int dstResNum;
uint16 fillColor;
- byte string1[4096];
- byte string2[4096];
- int field_2399;
- int field_239D;
- int field_23A1;
- int field_23A5;
- int field_23A9;
- int field_23AD;
- int field_23B1;
- int field_23B5;
- int field_23B9;
- int field_23BD;
- int field_23C1;
- int field_23C5;
- int field_23C9;
- int field_23CD;
+ FontProperties fontProperties;
+ EllipseProperties ellipseProperties;
Common::Rect box2;
- int field_23DE;
+ int blendFlags;
int spriteId;
int spriteGroup;
- int field_23EA;
+ int conditionBits;
WizImage img;
};
@@ -109,6 +117,9 @@ enum WizImageFlags {
kWIFMarkBufferDirty = 0x10,
kWIFBlitToMemBuffer = 0x20,
kWIFIsPolygon = 0x40,
+ kWIFZPlaneOn = 0x80,
+ kWIFZPlaneOff = 0x100,
+ kWIFUseShadow = 0x200,
kWIFFlipX = 0x400,
kWIFFlipY = 0x800
};
@@ -130,7 +141,31 @@ enum WizProcessFlags {
kWPFFillColor = 0x20000,
kWPFClipBox2 = 0x40000,
kWPFMaskImg = 0x80000,
- kWPFParams = 0x100000
+ kWPFParams = 0x100000,
+ kWPFZBuffer = 0x200000
+};
+
+enum WizCompositeFlags {
+ kWCFConditionBits = 0x01,
+ kWCFSubState = 0x02,
+ kWCFXDelta = 0x04,
+ kWCFYDelta = 0x08,
+ kWCFDrawFlags = 0x10,
+ kWCFSubConditionBits = 0x20
+};
+
+enum WizSpcConditionTypes {
+ kWSPCCTBits = 0xc0000000,
+ kWSPCCTOr = 0x00000000,
+ kWSPCCTAnd = 0x40000000,
+ kWSPCCTNot = 0x80000000
+};
+
+enum WizMoonSystemBits {
+ kWMSBRopMask = 0xff,
+ kWMSBRopParamMask = 0xff00,
+ kWMSBReservedBits = (kWMSBRopMask | kWMSBRopParamMask),
+ kWMSBRopParamRShift = 8
};
enum {
@@ -185,14 +220,19 @@ public:
void remapWizImagePal(const WizParameters *params);
void getWizImageDim(int resNum, int state, int32 &w, int32 &h);
+ void getWizImageDim(uint8 *dataPtr, int state, int32 &w, int32 &h);
int getWizImageStates(int resnum);
+ int getWizImageStates(const uint8 *ptr);
int isWizPixelNonTransparent(int resnum, int state, int x, int y, int flags);
+ int isWizPixelNonTransparent(uint8 *data, int state, int x, int y, int flags);
+ int isPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitdepth);
uint16 getWizPixelColor(int resnum, int state, int x, int y);
int getWizImageData(int resNum, int state, int type);
void flushWizBuffer();
void getWizImageSpot(int resId, int state, int32 &x, int32 &y);
+ void getWizImageSpot(uint8 *data, int state, int32 &x, int32 &y);
void loadWizCursor(int resId, int palette);
void captureWizImage(int resNum, const Common::Rect& r, bool frontBuffer, int compType);
@@ -202,7 +242,8 @@ public:
void displayWizImage(WizImage *pwi);
void processWizImage(const WizParameters *params);
- uint8 *drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int field_390, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr);
+ uint8 *drawWizImage(int resNum, int state, int maskNum, int maskState, int x1, int y1, int zorder, int shadow, int zbuffer, const Common::Rect *clipBox, int flags, int dstResNum, const uint8 *palPtr, uint32 conditionBits);
+ void drawWizImageEx(uint8 *dst, uint8 *src, uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *rect, int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits);
void drawWizPolygon(int resNum, int state, int id, int flags, int shadow, int dstResNum, int palette);
void drawWizComplexPolygon(int resNum, int state, int po_x, int po_y, int shadow, int angle, int zoom, const Common::Rect *r, int flags, int dstResNum, int palette);
void drawWizPolygonTransform(int resNum, int state, Common::Point *wp, int flags, int shadow, int dstResNum, int palette);
@@ -210,6 +251,12 @@ public:
#ifdef USE_RGB_COLOR
static void copyMaskWizImage(uint8 *dst, const uint8 *src, const uint8 *mask, int dstPitch, int dstType, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, const Common::Rect *rect, int flags, const uint8 *palPtr);
+
+ void copyCompositeWizImage(uint8 *dst, uint8 *wizPtr, uint8 *wizd, uint8 *maskPtr, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, int srcw, int srch, int state, const Common::Rect *clipBox,
+ int flags, const uint8 *palPtr, int transColor, uint8 bitDepth, const uint8 *xmapPtr, uint32 conditionBits);
+ void copy555WizImage(uint8 *dst, uint8 *wizd, int dstPitch, int dstType,
+ int dstw, int dsth, int srcx, int srcy, const Common::Rect *clipBox, uint32 conditionBits);
#endif
static void copyAuxImage(uint8 *dst1, uint8 *dst2, const uint8 *src, int dstw, int dsth, int srcx, int srcy, int srcw, int srch, uint8 bitdepth);
@@ -230,7 +277,6 @@ public:
template<int type> static void write8BitColor(uint8 *dst, const uint8 *src, int dstType, const uint8 *palPtr, const uint8 *xmapPtr, uint8 bitDepth);
static void writeColor(uint8 *dstPtr, int dstType, uint16 color);
- int isWizPixelNonTransparent(const uint8 *data, int x, int y, int w, int h, uint8 bitdepth);
uint16 getWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color);
uint16 getRawWizPixelColor(const uint8 *data, int x, int y, int w, int h, uint8 bitDepth, uint16 color);
void computeWizHistogram(uint32 *histogram, const uint8 *data, const Common::Rect& rCapt);
diff --git a/engines/scumm/imuse_digi/dimuse.h b/engines/scumm/imuse_digi/dimuse.h
index f04c2f7826..11b1ea678b 100644
--- a/engines/scumm/imuse_digi/dimuse.h
+++ b/engines/scumm/imuse_digi/dimuse.h
@@ -34,8 +34,10 @@
#include "scumm/music.h"
#include "scumm/sound.h"
-#include "audio/mixer.h"
-#include "audio/audiostream.h"
+namespace Audio {
+class AudioStream;
+class Mixer;
+}
namespace Scumm {
diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp
index 78d05c2051..b2ff3aadbb 100644
--- a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp
+++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp
@@ -22,8 +22,8 @@
#include "common/scummsys.h"
-#include "common/util.h"
+#include "audio/audiostream.h"
#include "audio/decoders/flac.h"
#include "audio/decoders/voc.h"
#include "audio/decoders/vorbis.h"
@@ -31,8 +31,6 @@
#include "scumm/resource.h"
#include "scumm/scumm.h"
-#include "scumm/util.h"
-#include "scumm/imuse_digi/dimuse.h"
#include "scumm/imuse_digi/dimuse_bndmgr.h"
#include "scumm/imuse_digi/dimuse_codecs.h"
#include "scumm/imuse_digi/dimuse_sndmgr.h"
diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.h b/engines/scumm/imuse_digi/dimuse_sndmgr.h
index aebf4d7f11..2f91405588 100644
--- a/engines/scumm/imuse_digi/dimuse_sndmgr.h
+++ b/engines/scumm/imuse_digi/dimuse_sndmgr.h
@@ -25,13 +25,20 @@
#include "common/scummsys.h"
-#include "audio/audiostream.h"
-#include "scumm/imuse_digi/dimuse_bndmgr.h"
+
+namespace Audio {
+class SeekableAudioStream;
+}
+
+namespace Common {
+class SeekableReadStream;
+}
namespace Scumm {
class ScummEngine;
class BundleMgr;
+class BundleDirCache;
class ImuseDigiSndMgr {
public:
diff --git a/engines/scumm/imuse_digi/dimuse_track.h b/engines/scumm/imuse_digi/dimuse_track.h
index 7e360268e5..a007903139 100644
--- a/engines/scumm/imuse_digi/dimuse_track.h
+++ b/engines/scumm/imuse_digi/dimuse_track.h
@@ -24,6 +24,11 @@
#define SCUMM_IMUSE_DIGI_TRACK_H
#include "common/scummsys.h"
+#include "audio/mixer.h"
+
+namespace Audio {
+class QueuingAudioStream;
+}
namespace Scumm {
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 1234eda3cc..6ef7e4d7f4 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -24,9 +24,7 @@
#include "common/events.h"
#include "common/system.h"
#include "common/translation.h"
-
-#include "gui/message.h"
-#include "gui/gui-manager.h"
+#include "audio/mixer.h"
#include "scumm/debugger.h"
#include "scumm/dialogs.h"
diff --git a/engines/scumm/midiparser_ro.cpp b/engines/scumm/midiparser_ro.cpp
index 35eb9f7eb7..5fc1ae41ab 100644
--- a/engines/scumm/midiparser_ro.cpp
+++ b/engines/scumm/midiparser_ro.cpp
@@ -22,9 +22,7 @@
#include "audio/midiparser.h"
-#include "audio/mididrv.h"
#include "common/textconsole.h"
-#include "common/util.h"
namespace Scumm {
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 416a8f7ef9..85ff1aa4cd 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -136,9 +136,20 @@ MODULE_OBJS += \
he/logic/basketball.o \
he/logic/football.o \
he/logic/funshop.o \
- he/logic/moonbase.o \
+ he/logic/moonbase_logic.o \
he/logic/puttrace.o \
- he/logic/soccer.o
+ he/logic/soccer.o \
+ he/moonbase/ai_defenseunit.o \
+ he/moonbase/ai_main.o \
+ he/moonbase/ai_node.o \
+ he/moonbase/ai_targetacquisition.o \
+ he/moonbase/ai_traveller.o \
+ he/moonbase/ai_tree.o \
+ he/moonbase/ai_types.o \
+ he/moonbase/ai_weapon.o \
+ he/moonbase/distortion.o \
+ he/moonbase/moonbase.o \
+ he/moonbase/moonbase_fow.o
endif
# This module can be built as a plugin
diff --git a/engines/scumm/object.cpp b/engines/scumm/object.cpp
index db836467ef..da94a34baf 100644
--- a/engines/scumm/object.cpp
+++ b/engines/scumm/object.cpp
@@ -1126,6 +1126,7 @@ void ScummEngine_v80he::clearDrawQueues() {
*/
void ScummEngine::markObjectRectAsDirty(int obj) {
int i, strip;
+ ++_V0Delay._objectRedrawCount;
for (i = 1; i < _numLocalObjects; i++) {
if (_objs[i].obj_nr == (uint16)obj) {
@@ -1133,6 +1134,7 @@ void ScummEngine::markObjectRectAsDirty(int obj) {
const int minStrip = MAX(_screenStartStrip, _objs[i].x_pos / 8);
const int maxStrip = MIN(_screenEndStrip+1, _objs[i].x_pos / 8 + _objs[i].width / 8);
for (strip = minStrip; strip < maxStrip; strip++) {
+ ++_V0Delay._objectStripRedrawCount;
setGfxUsageBit(strip, USAGE_BIT_DIRTY);
}
}
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index 4d4be2c3c2..55bbeeef98 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -50,7 +50,7 @@ Player_AD::Player_AD(ScummEngine *scumm)
writeReg(0x01, 0x20);
_engineMusicTimer = 0;
- _soundPlaying = -1;
+ _musicResource = -1;
_curOffset = 0;
@@ -104,8 +104,8 @@ void Player_AD::startSound(int sound) {
stopMusic();
// Lock the new music resource
- _soundPlaying = sound;
- _vm->_res->lock(rtSound, _soundPlaying);
+ _musicResource = sound;
+ _vm->_res->lock(rtSound, _musicResource);
// Start the new music resource
_musicData = res;
@@ -150,7 +150,7 @@ void Player_AD::startSound(int sound) {
void Player_AD::stopSound(int sound) {
Common::StackLock lock(_mutex);
- if (sound == _soundPlaying) {
+ if (sound == _musicResource) {
stopMusic();
} else {
for (int i = 0; i < ARRAYSIZE(_sfx); ++i) {
@@ -178,7 +178,17 @@ int Player_AD::getMusicTimer() {
}
int Player_AD::getSoundStatus(int sound) const {
- return (sound == _soundPlaying);
+ if (sound == _musicResource) {
+ return true;
+ }
+
+ for (int i = 0; i < ARRAYSIZE(_sfx); ++i) {
+ if (_sfx[i].resource == sound) {
+ return true;
+ }
+ }
+
+ return false;
}
void Player_AD::saveLoadWithSerializer(Serializer *ser) {
@@ -193,7 +203,7 @@ void Player_AD::saveLoadWithSerializer(Serializer *ser) {
if (ser->getVersion() >= VER(96)) {
int32 res[4] = {
- _soundPlaying, _sfx[0].resource, _sfx[1].resource, _sfx[2].resource
+ _musicResource, _sfx[0].resource, _sfx[1].resource, _sfx[2].resource
};
// The first thing we save is a list of sound resources being played
@@ -461,13 +471,13 @@ void Player_AD::startMusic() {
}
void Player_AD::stopMusic() {
- if (_soundPlaying == -1) {
+ if (_musicResource == -1) {
return;
}
// Unlock the music resource if present
- _vm->_res->unlock(rtSound, _soundPlaying);
- _soundPlaying = -1;
+ _vm->_res->unlock(rtSound, _musicResource);
+ _musicResource = -1;
// Stop the music playback
_curOffset = 0;
@@ -510,7 +520,7 @@ void Player_AD::updateMusic() {
// important to note that we need to parse a command directly
// at the new position, i.e. there is no time value we need to
// parse.
- if (_soundPlaying == -1) {
+ if (_musicResource == -1) {
return;
} else {
continue;
diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h
index 63fda3cc7c..1e665e82d5 100644
--- a/engines/scumm/players/player_ad.h
+++ b/engines/scumm/players/player_ad.h
@@ -25,8 +25,6 @@
#include "scumm/music.h"
-#include "audio/audiostream.h"
-
#include "common/mutex.h"
namespace OPL {
@@ -36,6 +34,7 @@ class OPL;
namespace Scumm {
class ScummEngine;
+class Serializer;
/**
* Sound output for v3/v4 AdLib data.
@@ -68,7 +67,7 @@ private:
OPL::OPL *_opl2;
- int _soundPlaying;
+ int _musicResource;
int32 _engineMusicTimer;
struct SfxSlot;
diff --git a/engines/scumm/players/player_apple2.h b/engines/scumm/players/player_apple2.h
index 8efb951f20..2e897d58f4 100644
--- a/engines/scumm/players/player_apple2.h
+++ b/engines/scumm/players/player_apple2.h
@@ -25,11 +25,9 @@
#include "common/mutex.h"
#include "common/scummsys.h"
-#include "common/memstream.h"
#include "scumm/music.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
-#include "audio/softsynth/sid.h"
namespace Scumm {
diff --git a/engines/scumm/players/player_mac.cpp b/engines/scumm/players/player_mac.cpp
index 634fd2de2b..87406f4e34 100644
--- a/engines/scumm/players/player_mac.cpp
+++ b/engines/scumm/players/player_mac.cpp
@@ -22,7 +22,6 @@
#include "common/macresman.h"
#include "engines/engine.h"
-#include "gui/message.h"
#include "scumm/players/player_mac.h"
#include "scumm/resource.h"
#include "scumm/scumm.h"
diff --git a/engines/scumm/players/player_v2cms.cpp b/engines/scumm/players/player_v2cms.cpp
index 08321932c3..1a1cd1ed8c 100644
--- a/engines/scumm/players/player_v2cms.cpp
+++ b/engines/scumm/players/player_v2cms.cpp
@@ -22,7 +22,6 @@
#include "scumm/players/player_v2cms.h"
#include "scumm/scumm.h"
-#include "audio/mididrv.h"
#include "audio/mixer.h"
#include "audio/softsynth/cms.h"
diff --git a/engines/scumm/players/player_v3m.h b/engines/scumm/players/player_v3m.h
index 81dda801fc..645f1fb1c9 100644
--- a/engines/scumm/players/player_v3m.h
+++ b/engines/scumm/players/player_v3m.h
@@ -28,10 +28,10 @@
#include "common/mutex.h"
#include "scumm/music.h"
#include "scumm/players/player_mac.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
+namespace Audio {
class Mixer;
+}
namespace Scumm {
diff --git a/engines/scumm/players/player_v5m.h b/engines/scumm/players/player_v5m.h
index f60a3f9346..152aa1541a 100644
--- a/engines/scumm/players/player_v5m.h
+++ b/engines/scumm/players/player_v5m.h
@@ -28,10 +28,10 @@
#include "common/mutex.h"
#include "scumm/music.h"
#include "scumm/players/player_mac.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
+namespace Audio {
class Mixer;
+}
namespace Scumm {
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index f3df24ff51..0ab36d1a96 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -41,8 +41,6 @@
#include "scumm/he/sprite_he.h"
#include "scumm/verbs.h"
-#include "audio/mixer.h"
-
#include "backends/audiocd/audiocd.h"
#include "graphics/thumbnail.h"
@@ -1139,6 +1137,10 @@ void ScummEngine::saveOrLoad(Serializer *s) {
if (s->isLoading() && s->getVersion() < VER(14))
upgradeGfxUsageBits();
+ // When loading, reset the ShakePos. Fixes one part of bug #7141
+ if (s->isLoading() && s->getVersion() >= VER(10))
+ _system->setShakePos(0);
+
// When loading, move the mouse to the saved mouse position.
if (s->isLoading() && s->getVersion() >= VER(20)) {
updateCursor();
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index 753287e217..fb2d45df8c 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -47,7 +47,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 97
+#define CURRENT_VER 98
/**
* An auxillary macro, used to specify savegame versions. We use this instead
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index 41c59cb521..68e4887b00 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 Tue Jan 12 23:47:54 2016
+ This file was generated by the md5table tool on Sat Apr 30 14:24:41 2016
DO NOT EDIT MANUALLY!
*/
@@ -189,6 +189,7 @@ static const MD5Table md5table[] = {
{ "3b832f4a90740bf22e9b8ed42ca0128c", "freddi4", "HE 99", "", -1, Common::EN_GRB, Common::kPlatformUnknown },
{ "3c4c471342bd95505a42334367d8f127", "puttmoon", "HE 70", "", 12161, Common::RU_RUS, Common::kPlatformWindows },
{ "3cce1913a3bc586b51a75c3892ff18dd", "indy3", "VGA", "VGA", -1, Common::RU_RUS, Common::kPlatformDOS },
+ { "3cf4b6ff78f735b671d8ccc2bc110b15", "maniac", "V2", "V2", -1, Common::ES_ESP, Common::kPlatformAmiga },
{ "3d219e7546039543307b55a91282bf18", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatformDOS },
{ "3de99ef0523f8ca7958faa3afccd035a", "spyfox", "HE 100", "Updated", -1, Common::EN_USA, Common::kPlatformUnknown },
{ "3df6ead57930488bc61e6e41901d0e97", "fbear", "HE 62", "", -1, Common::EN_ANY, Common::kPlatformMacintosh },
@@ -531,6 +532,7 @@ static const MD5Table md5table[] = {
{ "bf8b52fdd9a69c67f34e8e9fec72661c", "farm", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "bfdf584b01503f0762baded581f6a0a2", "SoccerMLS", "", "", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", 26159, Common::NL_NLD, Common::kPlatformWindows },
+ { "c0c9de81fb965e6cbe77f6e5631ca705", "monkey", "SE Talkie", "Unofficial SE Talkie v1.02", 9135, Common::EN_ANY, Common::kPlatformDOS },
{ "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD },
{ "c20848f53c2d48bfacdc840993843765", "freddi2", "HE 80", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown },
{ "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii },
@@ -671,6 +673,7 @@ static const MD5Table md5table[] = {
{ "f3c5d9bf3f091bd1f18dc1013fba5396", "atlantis", "Steam", "Steam", 638976, Common::EN_ANY, Common::kPlatformWindows },
{ "f3d55aea441e260e9e9c7d2a187097e0", "puttzoo", "", "Demo", 14337, Common::EN_ANY, Common::kPlatformWindows },
{ "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
+ { "f4d20ab4ce19743a646cb48bd93aee72", "monkey2", "SE Talkie", "Unofficial SE Talkie v0.2", 10835, Common::EN_ANY, Common::kPlatformDOS },
{ "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "f73883f13b5a302749a5bad31d909780", "tentacle", "", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh },
{ "f7635a0e2ab82c9a0f9ace5f232a488f", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 24d676a1ff..72c6909f8c 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -30,7 +30,6 @@
#include "engines/util.h"
#include "gui/message.h"
-#include "gui/gui-manager.h"
#include "graphics/cursorman.h"
@@ -67,6 +66,7 @@
#include "scumm/players/player_v5m.h"
#include "scumm/resource.h"
#include "scumm/he/resource_he.h"
+#include "scumm/he/moonbase/moonbase.h"
#include "scumm/scumm_v0.h"
#include "scumm/scumm_v8.h"
#include "scumm/sound.h"
@@ -733,8 +733,37 @@ ScummEngine_v0::ScummEngine_v0(OSystem *syst, const DetectorResult &dr)
VAR_IS_SOUND_RUNNING = 0xFF;
VAR_ACTIVE_VERB = 0xFF;
+ DelayReset();
+
if (strcmp(dr.fp.pattern, "maniacdemo.d64") == 0 )
- _game.features |= GF_DEMO;
+ _game.features |= GF_DEMO;
+}
+
+void ScummEngine_v0::DelayReset() {
+ _V0Delay._screenScroll = false;
+ _V0Delay._objectRedrawCount = 0;
+ _V0Delay._objectStripRedrawCount = 0;
+ _V0Delay._actorRedrawCount = 0;
+ _V0Delay._actorLimbRedrawDrawCount = 0;
+}
+
+int ScummEngine_v0::DelayCalculateDelta() {
+ float Time = 0;
+
+ // These values are made up, based on trial/error with visual inspection against WinVice
+ // If anyone feels inclined, the routines in the original engine could be profiled
+ // and these values changed accordindly.
+ Time += _V0Delay._objectRedrawCount * 7;
+ Time += _V0Delay._objectStripRedrawCount * 0.6;
+ Time += _V0Delay._actorRedrawCount * 2.0;
+ Time += _V0Delay._actorLimbRedrawDrawCount * 0.3;
+
+ if (_V0Delay._screenScroll)
+ Time += 3.6f;
+
+ DelayReset();
+
+ return floor(Time + 0.5);
}
ScummEngine_v6::ScummEngine_v6(OSystem *syst, const DetectorResult &dr)
@@ -805,6 +834,8 @@ ScummEngine_v70he::ScummEngine_v70he(OSystem *syst, const DetectorResult &dr)
_heSndChannel = 0;
_heSndFlags = 0;
_heSndSoundFreq = 0;
+ _heSndPan = 0;
+ _heSndVol = 0;
_numStoredFlObjects = 0;
_storedFlObjects = (ObjectData *)calloc(100, sizeof(ObjectData));
@@ -875,7 +906,7 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr)
memset(_videoParams.filename, 0, sizeof(_videoParams.filename));
_videoParams.status = 0;
_videoParams.flags = 0;
- _videoParams.unk2 = 0;
+ _videoParams.number = 0;
_videoParams.wizResNum = 0;
VAR_NUM_SPRITE_GROUPS = 0xFF;
@@ -898,6 +929,25 @@ ScummEngine_v90he::~ScummEngine_v90he() {
}
}
+ScummEngine_v100he::ScummEngine_v100he(OSystem *syst, const DetectorResult &dr) : ScummEngine_v99he(syst, dr) {
+ /* Moonbase stuff */
+ _moonbase = 0;
+
+ if (_game.id == GID_MOONBASE)
+ _moonbase = new Moonbase(this);
+
+ VAR_U32_USER_VAR_A = 0xFF;
+ VAR_U32_USER_VAR_B = 0xFF;
+ VAR_U32_USER_VAR_C = 0xFF;
+ VAR_U32_USER_VAR_D = 0xFF;
+ VAR_U32_USER_VAR_E = 0xFF;
+ VAR_U32_USER_VAR_F = 0xFF;
+}
+
+ScummEngine_v100he::~ScummEngine_v100he() {
+ delete _moonbase;
+}
+
ScummEngine_vCUPhe::ScummEngine_vCUPhe(OSystem *syst, const DetectorResult &dr) : Engine(syst){
_syst = syst;
_game = dr.game;
@@ -1275,10 +1325,7 @@ void ScummEngine::setupScumm() {
// On some systems it's not safe to run CD audio games from the CD.
if (_game.features & GF_AUDIOTRACKS && !Common::File::exists("CDDA.SOU")) {
checkCD();
-
- int cd_num = ConfMan.getInt("cdrom");
- if (cd_num >= 0)
- _system->getAudioCDManager()->openCD(cd_num);
+ _system->getAudioCDManager()->open();
}
// Create the sound manager
@@ -2061,13 +2108,24 @@ Common::Error ScummEngine::go() {
if (delta < 1) // Ensure we don't get into an endless loop
delta = 1; // by not decreasing sleepers.
- // WORKAROUND: walking speed in the original v0/v1 interpreter
+ // WORKAROUND: Unfortunately the MOS 6502 wasn't always fast enough for MM
+ // a number of situations can lead to the engine running at less than 60 ticks per second, without this drop
+ // - A single kid is able to escape via the Dungeon Door (after pushing the brick)
+ // - During the intro, calls to 'SetState08' are made for the lights on the mansion, with a 'breakHere'
+ // in between each, the reduction in ticks then occurs while affected stripes are being redrawn.
+ // The music buildup is then out of sync with the text "A Lucasfilm Games Production".
+ // Each call to 'breakHere' has been replaced with calls to 'Delay' in the V1/V2 versions of the game
+ if (_game.version == 0) {
+ delta += ((ScummEngine_v0 *)this)->DelayCalculateDelta();
+ }
+
+ // WORKAROUND: walking speed in the original v1 interpreter
// is sometimes slower (e.g. during scrolling) than in ScummVM.
// This is important for the door-closing action in the dungeon,
// otherwise (delta < 6) a single kid is able to escape.
- if ((_game.version == 0 && isScriptRunning(132)) ||
- (_game.version == 1 && isScriptRunning(137)))
- delta = 6;
+ if (_game.version == 1 && isScriptRunning(137)) {
+ delta = 6;
+ }
// Wait...
waitForTimer(delta * 1000 / 60 - diff);
@@ -2434,6 +2492,8 @@ void ScummEngine_v8::scummLoop_handleSaveLoad() {
void ScummEngine::scummLoop_handleDrawing() {
if (camera._cur != camera._last || _bgNeedsRedraw || _fullRedraw) {
+ _V0Delay._screenScroll = true;
+
redrawBGAreas();
}
@@ -2611,8 +2671,12 @@ bool ScummEngine::startManiac() {
Common::String path = dom.getVal("path");
if (path.hasPrefix(currentPath)) {
- path.erase(0, currentPath.size() + 1);
- if (path.equalsIgnoreCase("maniac")) {
+ path.erase(0, currentPath.size());
+ // Do a case-insensitive non-path-mode match of the remainder.
+ // While strictly speaking it's too broad, this matchString
+ // ignores the presence or absence of trailing path separators
+ // in either currentPath or path.
+ if (path.matchString("*maniac*", true, false)) {
maniacTarget = iter->_key;
break;
}
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 6e0adc3ff3..2906fc71f5 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SCUMM_H
-#define SCUMM_H
+#ifndef SCUMM_SCUMM_H
+#define SCUMM_SCUMM_H
#include "engines/engine.h"
@@ -298,7 +298,14 @@ struct StringTab : StringSlot {
}
};
+struct ScummEngine_v0_Delays {
+ bool _screenScroll;
+ uint _objectRedrawCount;
+ uint _objectStripRedrawCount;
+ uint _actorRedrawCount;
+ uint _actorLimbRedrawDrawCount;
+};
enum WhereIsObject {
WIO_NOT_FOUND = -1,
@@ -704,6 +711,7 @@ protected:
virtual int readVar(uint var);
virtual void writeVar(uint var, int value);
+protected:
void beginCutscene(int *args);
void endCutscene();
void abortCutscene();
@@ -1096,6 +1104,8 @@ public:
// Indy4 Amiga specific
byte *_verbPalette;
+ ScummEngine_v0_Delays _V0Delay;
+
protected:
int _shadowPaletteSize;
byte _currentPalette[3 * 256];
@@ -1130,6 +1140,8 @@ public:
byte getNumBoxes();
byte *getBoxMatrixBaseAddr();
+ byte *getBoxConnectionBase(int box);
+
int getNextBox(byte from, byte to);
void setBoxFlags(int box, int val);
diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h
index 4098d639c4..5f40940166 100644
--- a/engines/scumm/scumm_v0.h
+++ b/engines/scumm/scumm_v0.h
@@ -70,6 +70,10 @@ public:
byte walkboxFindTarget(Actor *a, int destbox, Common::Point walkdest);
+ /* Delay calculation */
+ void DelayReset();
+ int DelayCalculateDelta();
+
protected:
virtual void resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr = NULL);
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index e438008c1e..2a9e7a96e6 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -77,9 +77,11 @@ protected:
void getResultPosIndirect();
virtual void getResultPos();
+
virtual int readVar(uint var);
virtual void writeVar(uint var, int value);
+protected:
virtual int getActiveObject();
void ifStateCommon(byte type);
void ifNotStateCommon(byte type);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index 73268f6f33..83b9f2f4f8 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -119,7 +119,10 @@ protected:
ArrayHeader *getArray(int array);
byte *defineArray(int array, int type, int dim2, int dim1);
int findFreeArrayId();
+public: // FIXME. TODO
void nukeArray(int array);
+
+protected:
virtual int readArray(int array, int index, int base);
virtual void writeArray(int array, int index, int base, int value);
void shuffleArray(int num, int minIdx, int maxIdx);
diff --git a/engines/scumm/smush/smush_mixer.cpp b/engines/scumm/smush/smush_mixer.cpp
index 42e8f645be..445186d62b 100644
--- a/engines/scumm/smush/smush_mixer.cpp
+++ b/engines/scumm/smush/smush_mixer.cpp
@@ -21,14 +21,11 @@
*/
-#include "common/util.h"
-
#include "scumm/smush/smush_mixer.h"
#include "scumm/smush/channel.h"
#include "scumm/scumm.h"
-#include "scumm/sound.h"
-#include "scumm/imuse/imuse.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
diff --git a/engines/scumm/smush/smush_mixer.h b/engines/scumm/smush/smush_mixer.h
index 18ec7f96fb..1bd6adac16 100644
--- a/engines/scumm/smush/smush_mixer.h
+++ b/engines/scumm/smush/smush_mixer.h
@@ -28,6 +28,10 @@
#include "common/mutex.h"
#include "scumm/sound.h"
+namespace Audio {
+class QueuingAudioStream;
+}
+
namespace Scumm {
class SmushChannel;
diff --git a/engines/scumm/smush/smush_player.cpp b/engines/scumm/smush/smush_player.cpp
index 05c7ff2d9a..42ee0115c7 100644
--- a/engines/scumm/smush/smush_player.cpp
+++ b/engines/scumm/smush/smush_player.cpp
@@ -20,24 +20,21 @@
*
*/
-#include "engines/engine.h"
-
#include "common/config-manager.h"
#include "common/file.h"
#include "common/system.h"
#include "common/util.h"
+#include "audio/mixer.h"
+
#include "graphics/cursorman.h"
#include "graphics/palette.h"
-#include "scumm/bomp.h"
#include "scumm/file.h"
#include "scumm/imuse_digi/dimuse.h"
-#include "scumm/imuse/imuse.h"
#include "scumm/scumm.h"
#include "scumm/scumm_v7.h"
#include "scumm/sound.h"
-#include "scumm/util.h"
#include "scumm/smush/channel.h"
#include "scumm/smush/codec37.h"
#include "scumm/smush/codec47.h"
@@ -47,6 +44,7 @@
#include "scumm/insane/insane.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
@@ -246,9 +244,15 @@ SmushPlayer::SmushPlayer(ScummEngine_v7 *scumm) {
_paused = false;
_pauseStartTime = 0;
_pauseTime = 0;
+
+
+ _IACTchannel = new Audio::SoundHandle();
+ _compressedFileSoundHandle = new Audio::SoundHandle();
}
SmushPlayer::~SmushPlayer() {
+ delete _IACTchannel;
+ delete _compressedFileSoundHandle;
}
void SmushPlayer::init(int32 speed) {
@@ -275,8 +279,8 @@ void SmushPlayer::init(int32 speed) {
vs->pitch = vs->w;
_vm->_gdi->_numStrips = vs->w / 8;
- _vm->_mixer->stopHandle(_compressedFileSoundHandle);
- _vm->_mixer->stopHandle(_IACTchannel);
+ _vm->_mixer->stopHandle(*_compressedFileSoundHandle);
+ _vm->_mixer->stopHandle(*_IACTchannel);
_IACTpos = 0;
_vm->_smixer->stop();
}
@@ -474,7 +478,7 @@ void SmushPlayer::handleIACT(int32 subSize, Common::SeekableReadStream &b) {
if (!_IACTstream) {
_IACTstream = Audio::makeQueuingAudioStream(22050, true);
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_IACTchannel, _IACTstream);
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _IACTchannel, _IACTstream);
}
_IACTstream->queueBuffer(output_data, 0x1000, DisposeAfterUse::YES, Audio::FLAG_STEREO | Audio::FLAG_16BITS);
@@ -1095,7 +1099,7 @@ void SmushPlayer::seekSan(const char *file, int32 pos, int32 contFrame) {
}
void SmushPlayer::tryCmpFile(const char *filename) {
- _vm->_mixer->stopHandle(_compressedFileSoundHandle);
+ _vm->_mixer->stopHandle(*_compressedFileSoundHandle);
_compressedFileMode = false;
const char *i = strrchr(filename, '.');
@@ -1114,7 +1118,7 @@ void SmushPlayer::tryCmpFile(const char *filename) {
strcpy(fname + (i - filename), ".ogg");
if (file->open(fname)) {
_compressedFileMode = true;
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_compressedFileSoundHandle, Audio::makeVorbisStream(file, DisposeAfterUse::YES));
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _compressedFileSoundHandle, Audio::makeVorbisStream(file, DisposeAfterUse::YES));
return;
}
#endif
@@ -1123,7 +1127,7 @@ void SmushPlayer::tryCmpFile(const char *filename) {
strcpy(fname + (i - filename), ".mp3");
if (file->open(fname)) {
_compressedFileMode = true;
- _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_compressedFileSoundHandle, Audio::makeMP3Stream(file, DisposeAfterUse::YES));
+ _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _compressedFileSoundHandle, Audio::makeMP3Stream(file, DisposeAfterUse::YES));
return;
}
#endif
@@ -1189,12 +1193,12 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
// the sound. Synt to time instead.
now = _vm->_system->getMillis() - _pauseTime;
elapsed = now - _startTime;
- } else if (_vm->_mixer->isSoundHandleActive(_compressedFileSoundHandle)) {
+ } else if (_vm->_mixer->isSoundHandleActive(*_compressedFileSoundHandle)) {
// Compressed SMUSH files.
- elapsed = _vm->_mixer->getSoundElapsedTime(_compressedFileSoundHandle);
- } else if (_vm->_mixer->isSoundHandleActive(_IACTchannel)) {
+ elapsed = _vm->_mixer->getSoundElapsedTime(*_compressedFileSoundHandle);
+ } else if (_vm->_mixer->isSoundHandleActive(*_IACTchannel)) {
// Curse of Monkey Island SMUSH files.
- elapsed = _vm->_mixer->getSoundElapsedTime(_IACTchannel);
+ elapsed = _vm->_mixer->getSoundElapsedTime(*_IACTchannel);
} else {
// For other SMUSH files, we don't necessarily have any
// one channel to sync against, so we have to use
@@ -1249,8 +1253,8 @@ void SmushPlayer::play(const char *filename, int32 speed, int32 offset, int32 st
break;
if (_vm->shouldQuit() || _vm->_saveLoadFlag || _vm->_smushVideoShouldFinish) {
_smixer->stop();
- _vm->_mixer->stopHandle(_compressedFileSoundHandle);
- _vm->_mixer->stopHandle(_IACTchannel);
+ _vm->_mixer->stopHandle(*_compressedFileSoundHandle);
+ _vm->_mixer->stopHandle(*_IACTchannel);
_IACTpos = 0;
break;
}
diff --git a/engines/scumm/smush/smush_player.h b/engines/scumm/smush/smush_player.h
index 81c498a516..f1dffef7c7 100644
--- a/engines/scumm/smush/smush_player.h
+++ b/engines/scumm/smush/smush_player.h
@@ -24,7 +24,11 @@
#define SCUMM_SMUSH_PLAYER_H
#include "common/util.h"
-#include "scumm/sound.h"
+
+namespace Audio {
+class SoundHandle;
+class QueuingAudioStream;
+}
namespace Scumm {
@@ -61,10 +65,10 @@ private:
bool _skipNext;
uint32 _frame;
- Audio::SoundHandle _IACTchannel;
+ Audio::SoundHandle *_IACTchannel;
Audio::QueuingAudioStream *_IACTstream;
- Audio::SoundHandle _compressedFileSoundHandle;
+ Audio::SoundHandle *_compressedFileSoundHandle;
bool _compressedFileMode;
byte _IACToutput[4096];
int32 _IACTpos;
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 4d70ee8482..a62092f493 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -35,9 +35,9 @@
#include "scumm/resource.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
-#include "scumm/util.h"
-#include "audio/decoders/adpcm.h"
+#include "audio/audiostream.h"
+#include "audio/timestamp.h"
#include "audio/decoders/flac.h"
#include "audio/mididrv.h"
#include "audio/mixer.h"
@@ -45,7 +45,6 @@
#include "audio/decoders/raw.h"
#include "audio/decoders/voc.h"
#include "audio/decoders/vorbis.h"
-#include "audio/decoders/wave.h"
namespace Scumm {
@@ -98,15 +97,20 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer)
_loomSteamCD.balance = 0;
_isLoomSteam = _vm->_game.id == GID_LOOM && Common::File::exists("CDDA.SOU");
+
+ _loomSteamCDAudioHandle = new Audio::SoundHandle();
+ _talkChannelHandle = new Audio::SoundHandle();
}
Sound::~Sound() {
stopCDTimer();
stopCD();
free(_offsetTable);
+ delete _loomSteamCDAudioHandle;
+ delete _talkChannelHandle;
}
-void Sound::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags) {
+void Sound::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
if (_vm->VAR_LAST_SOUND != 0xFF)
_vm->VAR(_vm->VAR_LAST_SOUND) = sound;
_lastSound = sound;
@@ -115,15 +119,18 @@ void Sound::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags)
if (sound <= _vm->_numSounds)
_vm->ensureResourceLoaded(rtSound, sound);
- addSoundToQueue2(sound, heOffset, heChannel, heFlags);
+ addSoundToQueue2(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
}
-void Sound::addSoundToQueue2(int sound, int heOffset, int heChannel, int heFlags) {
+void Sound::addSoundToQueue2(int sound, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
assert(_soundQue2Pos < ARRAYSIZE(_soundQue2));
_soundQue2[_soundQue2Pos].sound = sound;
_soundQue2[_soundQue2Pos].offset = heOffset;
_soundQue2[_soundQue2Pos].channel = heChannel;
_soundQue2[_soundQue2Pos].flags = heFlags;
+ _soundQue2[_soundQue2Pos].freq = heFreq;
+ _soundQue2[_soundQue2Pos].pan = hePan;
+ _soundQue2[_soundQue2Pos].vol = heVol;
_soundQue2Pos++;
}
@@ -426,7 +433,7 @@ void Sound::processSfxQueues() {
if (_talk_sound_mode & 1)
startTalkSound(_talk_sound_a1, _talk_sound_b1, 1);
if (_talk_sound_mode & 2)
- startTalkSound(_talk_sound_a2, _talk_sound_b2, 2, &_talkChannelHandle);
+ startTalkSound(_talk_sound_a2, _talk_sound_b2, 2, _talkChannelHandle);
_talk_sound_mode = 0;
}
@@ -440,7 +447,7 @@ void Sound::processSfxQueues() {
} else if (_vm->_game.heversion >= 60) {
finished = !isSoundRunning(1);
} else {
- finished = !_mixer->isSoundHandleActive(_talkChannelHandle);
+ finished = !_mixer->isSoundHandleActive(*_talkChannelHandle);
}
if ((uint) act < 0x80 && ((_vm->_game.version == 8) || (_vm->_game.version <= 7 && !_vm->_string[0].no_talk_anim))) {
@@ -676,7 +683,7 @@ void Sound::stopTalkSound() {
} else if (_vm->_game.heversion >= 60) {
stopSound(1);
} else {
- _mixer->stopHandle(_talkChannelHandle);
+ _mixer->stopHandle(*_talkChannelHandle);
}
_sfxMode &= ~2;
}
@@ -802,6 +809,9 @@ void Sound::stopSound(int sound) {
_soundQue2[i].offset = 0;
_soundQue2[i].channel = 0;
_soundQue2[i].flags = 0;
+ _soundQue2[i].freq = 0;
+ _soundQue2[i].pan = 0;
+ _soundQue2[i].vol = 0;
}
}
}
@@ -1061,7 +1071,7 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
g_system->getAudioCDManager()->play(track, numLoops, startFrame, duration);
} else {
// Stop any currently playing track
- _mixer->stopHandle(_loomSteamCDAudioHandle);
+ _mixer->stopHandle(*_loomSteamCDAudioHandle);
Common::File *cddaFile = new Common::File();
if (cddaFile->open("CDDA.SOU")) {
@@ -1069,7 +1079,7 @@ void Sound::playCDTrackInternal(int track, int numLoops, int startFrame, int dur
Audio::Timestamp end = Audio::Timestamp(0, startFrame + duration, 75);
Audio::SeekableAudioStream *stream = makeCDDAStream(cddaFile, DisposeAfterUse::YES);
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_loomSteamCDAudioHandle,
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, _loomSteamCDAudioHandle,
Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
} else {
delete cddaFile;
@@ -1081,19 +1091,19 @@ void Sound::stopCD() {
if (!_isLoomSteam)
g_system->getAudioCDManager()->stop();
else
- _mixer->stopHandle(_loomSteamCDAudioHandle);
+ _mixer->stopHandle(*_loomSteamCDAudioHandle);
}
int Sound::pollCD() const {
if (!_isLoomSteam)
return g_system->getAudioCDManager()->isPlaying();
else
- return _mixer->isSoundHandleActive(_loomSteamCDAudioHandle);
+ return _mixer->isSoundHandleActive(*_loomSteamCDAudioHandle);
}
void Sound::updateCD() {
if (!_isLoomSteam)
- g_system->getAudioCDManager()->updateCD();
+ g_system->getAudioCDManager()->update();
}
AudioCDManager::Status Sound::getCDStatus() {
@@ -1101,7 +1111,7 @@ AudioCDManager::Status Sound::getCDStatus() {
return g_system->getAudioCDManager()->getStatus();
else {
AudioCDManager::Status info = _loomSteamCD;
- info.playing = _mixer->isSoundHandleActive(_loomSteamCDAudioHandle);
+ info.playing = _mixer->isSoundHandleActive(*_loomSteamCDAudioHandle);
return info;
}
}
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index a479ad5731..bc1e88f76b 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -24,23 +24,21 @@
#define SCUMM_SOUND_H
#include "common/scummsys.h"
-#include "audio/audiostream.h"
+#include "common/str.h"
#include "audio/mididrv.h"
-#include "audio/mixer.h"
#include "backends/audiocd/audiocd.h"
#include "scumm/saveload.h"
namespace Audio {
class Mixer;
+class SoundHandle;
}
namespace Scumm {
class ScummEngine;
-class BaseScummFile;
struct MP3OffsetTable;
-struct SaveLoadEntry;
enum {
kTalkSoundID = 10000
@@ -69,6 +67,9 @@ protected:
int32 offset;
int16 channel;
int16 flags;
+ int16 freq;
+ int16 pan;
+ int16 vol;
} _soundQue2[10];
Common::String _sfxFilename;
@@ -87,12 +88,12 @@ protected:
int16 _currentCDSound;
int16 _currentMusic;
- Audio::SoundHandle _loomSteamCDAudioHandle;
+ Audio::SoundHandle *_loomSteamCDAudioHandle;
bool _isLoomSteam;
AudioCDManager::Status _loomSteamCD;
public:
- Audio::SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on
+ Audio::SoundHandle *_talkChannelHandle; // Handle of mixer channel actor is talking on
bool _soundsPaused;
byte _sfxMode;
@@ -103,8 +104,8 @@ public:
public:
Sound(ScummEngine *parent, Audio::Mixer *mixer);
virtual ~Sound();
- virtual void addSoundToQueue(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0);
- virtual void addSoundToQueue2(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0);
+ virtual void addSoundToQueue(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0, int heFreq = 0, int hePan = 0, int heVol = 0);
+ virtual void addSoundToQueue2(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0, int heFreq = 0, int hePan = 0, int heVol = 0);
void processSound();
void playSound(int soundID);
diff --git a/engines/scumm/string.cpp b/engines/scumm/string.cpp
index 3049fbcf62..e6054918fa 100644
--- a/engines/scumm/string.cpp
+++ b/engines/scumm/string.cpp
@@ -23,6 +23,7 @@
#include "common/config-manager.h"
+#include "audio/mixer.h"
#include "scumm/actor.h"
#include "scumm/charset.h"
@@ -662,7 +663,7 @@ void ScummEngine::CHARSET_1() {
// Special case for HE games
} else if (_game.id == GID_LOOM && !ConfMan.getBool("subtitles") && (_sound->pollCD())) {
// Special case for Loom (CD), since it only uses CD audio.for sound
- } else if (!ConfMan.getBool("subtitles") && (!_haveActorSpeechMsg || _mixer->isSoundHandleActive(_sound->_talkChannelHandle))) {
+ } else if (!ConfMan.getBool("subtitles") && (!_haveActorSpeechMsg || _mixer->isSoundHandleActive(*_sound->_talkChannelHandle))) {
// Subtitles are turned off, and there is a voice version
// of this message -> don't print it.
} else {
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index a6be5c3f3a..e5ba4a68ee 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -341,6 +341,19 @@ void ScummEngine_v90he::setupScummVars() {
VAR_NUM_UNK = 131;
}
}
+
+void ScummEngine_v100he::setupScummVars() {
+ ScummEngine_v90he::setupScummVars();
+
+ if (_game.id == GID_MOONBASE) {
+ VAR_U32_USER_VAR_A = 108;
+ VAR_U32_USER_VAR_B = 109;
+ VAR_U32_USER_VAR_C = 110;
+ VAR_U32_USER_VAR_D = 111;
+ VAR_U32_USER_VAR_E = 112;
+ VAR_U32_USER_VAR_F = 113;
+ }
+}
#endif
#ifdef ENABLE_SCUMM_7_8
diff --git a/engines/sherlock/animation.cpp b/engines/sherlock/animation.cpp
index 681e71d0f6..4442c1da85 100644
--- a/engines/sherlock/animation.cpp
+++ b/engines/sherlock/animation.cpp
@@ -23,6 +23,8 @@
#include "sherlock/animation.h"
#include "sherlock/sherlock.h"
#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/3do/scalpel_3do_screen.h"
+
#include "common/algorithm.h"
namespace Sherlock {
@@ -89,7 +91,7 @@ bool Animation::play(const Common::String &filename, bool intro, int minDelay, i
// Draw the sprite. Note that we explicitly use the raw frame below, rather than the ImageFrame,
// since we don't want the offsets in the image file to be used, just the explicit position we specify
- screen.transBlitFrom(images[imageFrame]._frame, pt);
+ screen.SHtransBlitFrom(images[imageFrame]._frame, pt);
} else {
// At this point, either the sprites for the frame has been complete, or there weren't any sprites
// at all to draw for the frame
@@ -201,7 +203,7 @@ bool Animation::play3DO(const Common::String &filename, bool intro, int minDelay
// Draw the sprite. Note that we explicitly use the raw frame below, rather than the ImageFrame,
// since we don't want the offsets in the image file to be used, just the explicit position we specify
- screen._backBuffer1.transBlitFrom(images[imageFrame]._frame, pt);
+ screen._backBuffer1.SHtransBlitFrom(images[imageFrame]._frame, pt);
if (!fadeActive)
screen.slamArea(pt.x, pt.y, images[imageFrame]._frame.w, images[imageFrame]._frame.h);
} else {
diff --git a/engines/sherlock/debugger.cpp b/engines/sherlock/debugger.cpp
index 39f8da3806..55243c4bc7 100644
--- a/engines/sherlock/debugger.cpp
+++ b/engines/sherlock/debugger.cpp
@@ -26,9 +26,6 @@
#include "sherlock/scalpel/scalpel.h"
#include "sherlock/scalpel/scalpel_debugger.h"
#include "sherlock/tattoo/tattoo_debugger.h"
-#include "audio/mixer.h"
-#include "audio/decoders/aiff.h"
-#include "audio/decoders/wave.h"
#include "common/str-array.h"
namespace Sherlock {
diff --git a/engines/sherlock/events.cpp b/engines/sherlock/events.cpp
index 4b0b7dfb3f..6cfee5d822 100644
--- a/engines/sherlock/events.cpp
+++ b/engines/sherlock/events.cpp
@@ -143,7 +143,7 @@ void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const
// Form a single surface containing both frames
Surface s(r.width(), r.height());
- s.fill(TRANSPARENCY);
+ s.clear(TRANSPARENCY);
// Draw the passed image
Common::Point drawPos;
@@ -151,11 +151,11 @@ void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const
drawPos.x = -cursorPt.x;
if (cursorPt.y < 0)
drawPos.y = -cursorPt.y;
- s.blitFrom(surface, Common::Point(drawPos.x, drawPos.y));
+ s.SHblitFrom(surface, Common::Point(drawPos.x, drawPos.y));
// Draw the cursor image
drawPos = Common::Point(MAX(cursorPt.x, (int16)0), MAX(cursorPt.y, (int16)0));
- s.transBlitFrom(cursorImg, Common::Point(drawPos.x, drawPos.y));
+ s.SHtransBlitFrom(cursorImg, Common::Point(drawPos.x, drawPos.y));
// Set up hotspot position for cursor, adjusting for cursor image's position within the surface
Common::Point hotspot;
@@ -163,7 +163,7 @@ void Events::setCursor(CursorId cursorId, const Common::Point &cursorPos, const
hotspot = Common::Point(8, 8);
hotspot += drawPos;
// Set the cursor
- setCursor(s.getRawSurface(), hotspot.x, hotspot.y);
+ setCursor(s, hotspot.x, hotspot.y);
}
void Events::animateCursorIfNeeded() {
diff --git a/engines/sherlock/fonts.cpp b/engines/sherlock/fonts.cpp
index 8e36c3908a..dc7ecd521e 100644
--- a/engines/sherlock/fonts.cpp
+++ b/engines/sherlock/fonts.cpp
@@ -43,7 +43,7 @@ void Fonts::setVm(SherlockEngine *vm) {
_charCount = 0;
}
-void Fonts::free() {
+void Fonts::freeFont() {
delete _font;
}
@@ -195,7 +195,7 @@ inline byte Fonts::translateChar(byte c) {
}
}
-void Fonts::writeString(Surface *surface, const Common::String &str,
+void Fonts::writeString(BaseSurface *surface, const Common::String &str,
const Common::Point &pt, int overrideColor) {
Common::Point charPos = pt;
@@ -213,7 +213,7 @@ void Fonts::writeString(Surface *surface, const Common::String &str,
if (curChar < _charCount) {
ImageFrame &frame = (*_font)[curChar];
- surface->transBlitFrom(frame, Common::Point(charPos.x, charPos.y + _yOffsets[curChar]), false, overrideColor);
+ surface->SHtransBlitFrom(frame, Common::Point(charPos.x, charPos.y + _yOffsets[curChar]), false, overrideColor);
charPos.x += frame._frame.w + 1;
} else {
warning("Invalid character encountered - %d", (int)curChar);
diff --git a/engines/sherlock/fonts.h b/engines/sherlock/fonts.h
index a527cc73c0..6c805447b3 100644
--- a/engines/sherlock/fonts.h
+++ b/engines/sherlock/fonts.h
@@ -31,7 +31,7 @@ namespace Sherlock {
class SherlockEngine;
class ImageFile;
-class Surface;
+class BaseSurface;
class Fonts {
private:
@@ -44,7 +44,7 @@ protected:
static int _widestChar;
static uint16 _charCount;
- static void writeString(Surface *surface, const Common::String &str,
+ static void writeString(BaseSurface *surface, const Common::String &str,
const Common::Point &pt, int overrideColor = 0);
static inline byte translateChar(byte c);
@@ -57,7 +57,7 @@ public:
/**
* Frees the font manager
*/
- static void free();
+ static void freeFont();
/**
* Set the font to use for writing text on the screen
diff --git a/engines/sherlock/image_file.cpp b/engines/sherlock/image_file.cpp
index 1247a7f8d0..c53e537bb8 100644
--- a/engines/sherlock/image_file.cpp
+++ b/engines/sherlock/image_file.cpp
@@ -302,12 +302,6 @@ ImageFile3DO::ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData)
}
}
-ImageFile3DO::~ImageFile3DO() {
- // already done in ImageFile destructor
- //for (uint idx = 0; idx < size(); ++idx)
- // (*this)[idx]._frame.free();
-}
-
void ImageFile3DO::load(Common::SeekableReadStream &stream, bool isRoomData) {
uint32 headerId = 0;
@@ -380,7 +374,7 @@ void ImageFile3DO::loadAnimationFile(Common::SeekableReadStream &stream) {
if (streamLeft < celDataSize)
error("load3DOAnimationFile: expected cel data, not enough bytes");
- //
+ //
// Load data for frame and decompress it
byte *data = new byte[celDataSize];
stream.read(data, celDataSize);
@@ -683,7 +677,7 @@ void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
if (ccbFlags & 0x200) // bit 9
ccbFlags_compressed = true;
-
+
// PRE0 first 3 bits define how many bits per encoded pixel are used
ccbPRE0_bitsPerPixel = imagefile3DO_cel_bitsPerPixelLookupTable[ccbPRE0 & 0x07];
if (!ccbPRE0_bitsPerPixel)
@@ -713,7 +707,7 @@ void ImageFile3DO::load3DOCelRoomData(Common::SeekableReadStream &stream) {
stream.read(celDataPtr, celDataSize);
streamLeft -= celDataSize;
-
+
// Set up frame
{
ImageFrame imageFrame;
diff --git a/engines/sherlock/image_file.h b/engines/sherlock/image_file.h
index da260ab30b..0ae7cc1dcb 100644
--- a/engines/sherlock/image_file.h
+++ b/engines/sherlock/image_file.h
@@ -46,6 +46,11 @@ struct ImageFrame {
Graphics::Surface _frame;
/**
+ * Converts an ImageFrame record to a surface for convenience in passing to drawing methods
+ */
+ operator const Graphics::Surface &() { return _frame; }
+
+ /**
* Decompress a single frame for the sprite
*/
void decompressFrame(const byte *src, bool isRoseTattoo);
@@ -90,7 +95,7 @@ public:
ImageFile();
ImageFile(const Common::String &name, bool skipPal = false, bool animImages = false);
ImageFile(Common::SeekableReadStream &stream, bool skipPal = false);
- ~ImageFile();
+ virtual ~ImageFile();
static void setVm(SherlockEngine *vm);
};
@@ -150,7 +155,6 @@ private:
public:
ImageFile3DO(const Common::String &name, ImageFile3DOType imageFile3DOType);
ImageFile3DO(Common::SeekableReadStream &stream, bool isRoomData = false);
- ~ImageFile3DO();
static void setVm(SherlockEngine *vm);
};
diff --git a/engines/sherlock/module.mk b/engines/sherlock/module.mk
index 7fa7896691..0d17d0b249 100644
--- a/engines/sherlock/module.mk
+++ b/engines/sherlock/module.mk
@@ -3,6 +3,7 @@ MODULE := engines/sherlock
MODULE_OBJS = \
scalpel/scalpel.o \
scalpel/3do/movie_decoder.o \
+ scalpel/3do/scalpel_3do_screen.o \
scalpel/drivers/adlib.o \
scalpel/drivers/mt32.o \
scalpel/tsage/logo.o \
@@ -30,6 +31,7 @@ MODULE_OBJS = \
tattoo/tattoo_people.o \
tattoo/tattoo_resources.o \
tattoo/tattoo_scene.o \
+ tattoo/tattoo_screen.o \
tattoo/tattoo_talk.o \
tattoo/tattoo_user_interface.o \
tattoo/widget_base.o \
diff --git a/engines/sherlock/music.cpp b/engines/sherlock/music.cpp
index 5ea3318bd7..da4aec6994 100644
--- a/engines/sherlock/music.cpp
+++ b/engines/sherlock/music.cpp
@@ -26,6 +26,7 @@
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/scalpel/drivers/mididriver.h"
+#include "audio/audiostream.h"
// for Miles Audio (Sherlock Holmes 2)
#include "audio/miles.h"
// for 3DO digital music
@@ -225,6 +226,7 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
_midiOption = false;
_midiMusicData = nullptr;
_musicVolume = ConfMan.hasKey("music_volume") ? ConfMan.getInt("music_volume") : 255;
+ _musicOn = false;
if (IS_3DO) {
// 3DO - uses digital samples for music
diff --git a/engines/sherlock/music.h b/engines/sherlock/music.h
index 186e2aa2dc..b1eba1d889 100644
--- a/engines/sherlock/music.h
+++ b/engines/sherlock/music.h
@@ -23,12 +23,9 @@
#ifndef SHERLOCK_MUSIC_H
#define SHERLOCK_MUSIC_H
-#include "audio/midiplayer.h"
#include "audio/midiparser.h"
-//#include "audio/mididrv.h"
-#include "sherlock/scalpel/drivers/mididriver.h"
+#include "audio/mididrv.h"
// for 3DO digital music
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/mutex.h"
#include "common/str-array.h"
diff --git a/engines/sherlock/objects.cpp b/engines/sherlock/objects.cpp
index a89b8dce86..a05351b170 100644
--- a/engines/sherlock/objects.cpp
+++ b/engines/sherlock/objects.cpp
@@ -365,8 +365,8 @@ bool BaseObject::checkEndOfSequence() {
if (seq == 99) {
--_frameNumber;
- screen._backBuffer1.transBlitFrom(*_imageFrame, _position);
- screen._backBuffer2.transBlitFrom(*_imageFrame, _position);
+ screen._backBuffer1.SHtransBlitFrom(*_imageFrame, _position);
+ screen._backBuffer2.SHtransBlitFrom(*_imageFrame, _position);
_type = INVALID;
} else if (IS_ROSE_TATTOO && _talkSeq && seq == 0) {
setObjTalkSequence(_talkSeq);
@@ -636,7 +636,9 @@ void Sprite::clear() {
_altImages = nullptr;
_altSeq = 0;
_centerWalk = 0;
- Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
+
+ for (int i = 0; i < 8; i++)
+ _stopFrames[i] = nullptr;
}
void Sprite::setImageFrame() {
diff --git a/engines/sherlock/saveload.cpp b/engines/sherlock/saveload.cpp
index f32552c7ea..45a4eedb10 100644
--- a/engines/sherlock/saveload.cpp
+++ b/engines/sherlock/saveload.cpp
@@ -89,7 +89,7 @@ SaveStateList SaveManager::getSavegameList(const Common::String &target) {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String saveDesc;
- Common::String pattern = Common::String::format("%s.0??", target.c_str());
+ Common::String pattern = Common::String::format("%s.0##", target.c_str());
SherlockSavegameHeader header;
filenames = saveFileMan->listSavefiles(pattern);
diff --git a/engines/sherlock/scalpel/3do/movie_decoder.cpp b/engines/sherlock/scalpel/3do/movie_decoder.cpp
index da4d08ca47..da0d16c145 100644
--- a/engines/sherlock/scalpel/3do/movie_decoder.cpp
+++ b/engines/sherlock/scalpel/3do/movie_decoder.cpp
@@ -25,7 +25,6 @@
#include "common/textconsole.h"
#include "audio/audiostream.h"
-#include "audio/decoders/raw.h"
#include "audio/decoders/3do.h"
#include "sherlock/scalpel/3do/movie_decoder.h"
diff --git a/engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp b/engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp
new file mode 100644
index 0000000000..f8112d8add
--- /dev/null
+++ b/engines/sherlock/scalpel/3do/scalpel_3do_screen.cpp
@@ -0,0 +1,286 @@
+/* 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.
+ *
+ */
+
+#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/scalpel.h"
+#include "sherlock/scalpel/3do/scalpel_3do_screen.h"
+
+namespace Sherlock {
+
+namespace Scalpel {
+
+Scalpel3DOScreen::Scalpel3DOScreen(SherlockEngine *vm): ScalpelScreen(vm) {
+}
+
+void Scalpel3DOScreen::SHblitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) {
+ if (!_vm->_isScreenDoubled) {
+ ScalpelScreen::SHblitFrom(src, pt, srcBounds);
+ return;
+ }
+
+ Common::Rect srcRect = srcBounds;
+ Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height());
+
+ if (!srcRect.isValidRect() || !clip(srcRect, destRect))
+ return;
+
+ // Add dirty area remapped to the 640x200 surface
+ addDirtyRect(Common::Rect(destRect.left * 2, destRect.top * 2, destRect.right * 2, destRect.bottom * 2));
+
+ // Transfer the area, doubling each pixel
+ for (int yp = 0; yp < srcRect.height(); ++yp) {
+ const uint16 *srcP = (const uint16 *)src.getBasePtr(srcRect.left, srcRect.top + yp);
+ uint16 *destP = (uint16 *)getBasePtr(destRect.left * 2, (destRect.top + yp) * 2);
+
+ for (int xp = srcRect.left; xp < srcRect.right; ++xp, ++srcP, destP += 2) {
+ *destP = *srcP;
+ *(destP + 1) = *srcP;
+ *(destP + 640) = *srcP;
+ *(destP + 640 + 1) = *srcP;
+ }
+ }
+}
+
+void Scalpel3DOScreen::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt,
+ bool flipped, int overrideColor) {
+ error("TODO: Refactor");
+#if 0
+ if (!_vm->_isScreenDoubled) {
+ ScalpelScreen::transBlitFromUnscaled(src, pt, flipped, overrideColor);
+ return;
+ }
+
+ Common::Rect drawRect(0, 0, src.w, src.h);
+ Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h);
+
+ // Clip the display area to on-screen
+ if (!clip(drawRect, destRect))
+ // It's completely off-screen
+ return;
+
+ if (flipped)
+ drawRect = Common::Rect(src.w - drawRect.right, src.h - drawRect.bottom,
+ src.w - drawRect.left, src.h - drawRect.top);
+
+ Common::Point destPt(destRect.left, destRect.top);
+ addDirtyRect(Common::Rect(destPt.x * 2, destPt.y * 2, (destPt.x + drawRect.width()) * 2,
+ (destPt.y + drawRect.height()) * 2));
+
+ assert(src.format.bytesPerPixel == 2 && _surface.format.bytesPerPixel == 2);
+
+ for (int yp = 0; yp < drawRect.height(); ++yp) {
+ const uint16 *srcP = (const uint16 *)src.getBasePtr(
+ flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp);
+ uint16 *destP = (uint16 *)getBasePtr(destPt.x * 2, (destPt.y + yp) * 2);
+
+ for (int xp = 0; xp < drawRect.width(); ++xp, destP += 2) {
+ // RGB 0, 0, 0 -> transparent on 3DO
+ if (*srcP) {
+ *destP = *srcP;
+ *(destP + 1) = *srcP;
+ *(destP + 640) = *srcP;
+ *(destP + 640 + 1) = *srcP;
+ }
+
+ srcP = flipped ? srcP - 1 : srcP + 1;
+ }
+ }
+#endif
+}
+
+void Scalpel3DOScreen::fillRect(const Common::Rect &r, uint color) {
+ if (_vm->_isScreenDoubled)
+ ScalpelScreen::fillRect(Common::Rect(r.left * 2, r.top * 2, r.right * 2, r.bottom * 2), color);
+ else
+ ScalpelScreen::fillRect(r, color);
+}
+
+void Scalpel3DOScreen::fadeIntoScreen3DO(int speed) {
+ Events &events = *_vm->_events;
+ uint16 *currentScreenBasePtr = (uint16 *)getPixels();
+ uint16 *targetScreenBasePtr = (uint16 *)_backBuffer.getPixels();
+ uint16 currentScreenPixel = 0;
+ uint16 targetScreenPixel = 0;
+
+ uint16 currentScreenPixelRed = 0;
+ uint16 currentScreenPixelGreen = 0;
+ uint16 currentScreenPixelBlue = 0;
+
+ uint16 targetScreenPixelRed = 0;
+ uint16 targetScreenPixelGreen = 0;
+ uint16 targetScreenPixelBlue = 0;
+
+ uint16 screenWidth = SHERLOCK_SCREEN_WIDTH;
+ uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT;
+ uint16 screenX = 0;
+ uint16 screenY = 0;
+ uint16 pixelsChanged = 0;
+
+ clearDirtyRects();
+
+ do {
+ pixelsChanged = 0;
+ uint16 *currentScreenPtr = currentScreenBasePtr;
+ uint16 *targetScreenPtr = targetScreenBasePtr;
+
+ for (screenY = 0; screenY < screenHeight; screenY++) {
+ for (screenX = 0; screenX < screenWidth; screenX++) {
+ currentScreenPixel = *currentScreenPtr;
+ targetScreenPixel = *targetScreenPtr;
+
+ if (currentScreenPixel != targetScreenPixel) {
+ // pixel doesn't match, adjust accordingly
+ currentScreenPixelRed = currentScreenPixel & 0xF800;
+ currentScreenPixelGreen = currentScreenPixel & 0x07E0;
+ currentScreenPixelBlue = currentScreenPixel & 0x001F;
+ targetScreenPixelRed = targetScreenPixel & 0xF800;
+ targetScreenPixelGreen = targetScreenPixel & 0x07E0;
+ targetScreenPixelBlue = targetScreenPixel & 0x001F;
+
+ if (currentScreenPixelRed != targetScreenPixelRed) {
+ if (currentScreenPixelRed < targetScreenPixelRed) {
+ currentScreenPixelRed += 0x0800;
+ } else {
+ currentScreenPixelRed -= 0x0800;
+ }
+ }
+ if (currentScreenPixelGreen != targetScreenPixelGreen) {
+ // Adjust +2/-2 because we are running RGB555 at RGB565
+ if (currentScreenPixelGreen < targetScreenPixelGreen) {
+ currentScreenPixelGreen += 0x0040;
+ } else {
+ currentScreenPixelGreen -= 0x0040;
+ }
+ }
+ if (currentScreenPixelBlue != targetScreenPixelBlue) {
+ if (currentScreenPixelBlue < targetScreenPixelBlue) {
+ currentScreenPixelBlue += 0x0001;
+ } else {
+ currentScreenPixelBlue -= 0x0001;
+ }
+ }
+
+ uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
+ *currentScreenPtr = v;
+ if (_vm->_isScreenDoubled) {
+ *(currentScreenPtr + 1) = v;
+ *(currentScreenPtr + 640) = v;
+ *(currentScreenPtr + 640 + 1) = v;
+ }
+
+ pixelsChanged++;
+ }
+
+ currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1;
+ targetScreenPtr++;
+ }
+
+ if (_vm->_isScreenDoubled)
+ currentScreenPtr += 640;
+ }
+
+ // Too much considered dirty at the moment
+ if (_vm->_isScreenDoubled)
+ addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2));
+ else
+ addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight));
+
+ events.pollEvents();
+ events.delay(10 * speed);
+ } while ((pixelsChanged) && (!_vm->shouldQuit()));
+}
+
+void Scalpel3DOScreen::blitFrom3DOcolorLimit(uint16 limitColor) {
+ uint16 *currentScreenPtr = (uint16 *)getPixels();
+ uint16 *targetScreenPtr = (uint16 *)_backBuffer.getPixels();
+ uint16 currentScreenPixel = 0;
+
+ uint16 screenWidth = SHERLOCK_SCREEN_WIDTH;
+ uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT;
+ uint16 screenX = 0;
+ uint16 screenY = 0;
+
+ uint16 currentScreenPixelRed = 0;
+ uint16 currentScreenPixelGreen = 0;
+ uint16 currentScreenPixelBlue = 0;
+
+ uint16 limitPixelRed = limitColor & 0xF800;
+ uint16 limitPixelGreen = limitColor & 0x07E0;
+ uint16 limitPixelBlue = limitColor & 0x001F;
+
+ for (screenY = 0; screenY < screenHeight; screenY++) {
+ for (screenX = 0; screenX < screenWidth; screenX++) {
+ currentScreenPixel = *targetScreenPtr;
+
+ currentScreenPixelRed = currentScreenPixel & 0xF800;
+ currentScreenPixelGreen = currentScreenPixel & 0x07E0;
+ currentScreenPixelBlue = currentScreenPixel & 0x001F;
+
+ if (currentScreenPixelRed < limitPixelRed)
+ currentScreenPixelRed = limitPixelRed;
+ if (currentScreenPixelGreen < limitPixelGreen)
+ currentScreenPixelGreen = limitPixelGreen;
+ if (currentScreenPixelBlue < limitPixelBlue)
+ currentScreenPixelBlue = limitPixelBlue;
+
+ uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
+ *currentScreenPtr = v;
+ if (_vm->_isScreenDoubled) {
+ *(currentScreenPtr + 1) = v;
+ *(currentScreenPtr + 640) = v;
+ *(currentScreenPtr + 640 + 1) = v;
+ }
+
+ currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1;
+ targetScreenPtr++;
+ }
+
+ if (_vm->_isScreenDoubled)
+ currentScreenPtr += 640;
+ }
+
+ // Too much considered dirty at the moment
+ if (_vm->_isScreenDoubled)
+ addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2));
+ else
+ addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight));
+}
+
+uint16 Scalpel3DOScreen::width() const {
+ return _vm->_isScreenDoubled ? this->w / 2 : this->w;
+}
+
+uint16 Scalpel3DOScreen::height() const {
+ return _vm->_isScreenDoubled ? this->h / 2 : this->h;
+}
+
+void Scalpel3DOScreen::rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt) {
+ Common::Rect srcRect(0, 0, src.w, src.h);
+ Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h);
+
+ addDirtyRect(destRect);
+ copyRectToSurface(src, destRect.left, destRect.top, srcRect);
+}
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/3do/scalpel_3do_screen.h b/engines/sherlock/scalpel/3do/scalpel_3do_screen.h
new file mode 100644
index 0000000000..422f588b17
--- /dev/null
+++ b/engines/sherlock/scalpel/3do/scalpel_3do_screen.h
@@ -0,0 +1,76 @@
+/* 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.
+ *
+ */
+
+#ifndef SHERLOCK_SCALPEL_3DO_SCREEN_H
+#define SHERLOCK_SCALPEL_3DO_SCREEN_H
+
+#include "sherlock/scalpel/scalpel_screen.h"
+
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Scalpel {
+
+class Scalpel3DOScreen : public ScalpelScreen {
+protected:
+ /**
+ * Draws a sub-section of a surface at a given position within this surface
+ * Overriden for the 3DO to automatically double the size of everything to the underlying 640x400 surface
+ */
+ virtual void SHblitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
+
+ /**
+ * Draws a surface at a given position within this surface with transparency
+ */
+ virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped,
+ int overrideColor);
+public:
+ Scalpel3DOScreen(SherlockEngine *vm);
+ virtual ~Scalpel3DOScreen() {}
+
+ /**
+ * Draws a sub-section of a surface at a given position within this surface
+ */
+ void rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt);
+
+ /**
+ * Fade backbuffer 1 into screen (3DO RGB!)
+ */
+ void fadeIntoScreen3DO(int speed);
+
+ void blitFrom3DOcolorLimit(uint16 color);
+
+ /**
+ * Fill a given area of the surface with a given color
+ */
+ virtual void fillRect(const Common::Rect &r, uint color);
+
+ virtual uint16 width() const;
+ virtual uint16 height() const;
+};
+
+} // End of namespace Scalpel
+
+} // End of namespace Sherlock
+
+#endif
diff --git a/engines/sherlock/scalpel/drivers/adlib.cpp b/engines/sherlock/scalpel/drivers/adlib.cpp
index 29a39f0c39..3d29d0c5ed 100644
--- a/engines/sherlock/scalpel/drivers/adlib.cpp
+++ b/engines/sherlock/scalpel/drivers/adlib.cpp
@@ -21,14 +21,12 @@
*/
#include "sherlock/sherlock.h"
-#include "sherlock/scalpel/drivers/mididriver.h"
-#include "common/file.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "audio/fmopl.h"
-#include "audio/softsynth/emumidi.h"
+#include "audio/mididrv.h"
namespace Sherlock {
diff --git a/engines/sherlock/scalpel/scalpel.cpp b/engines/sherlock/scalpel/scalpel.cpp
index b17f38b218..cbb202095f 100644
--- a/engines/sherlock/scalpel/scalpel.cpp
+++ b/engines/sherlock/scalpel/scalpel.cpp
@@ -29,6 +29,7 @@
#include "sherlock/scalpel/scalpel_people.h"
#include "sherlock/scalpel/scalpel_scene.h"
#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/3do/scalpel_3do_screen.h"
#include "sherlock/scalpel/tsage/logo.h"
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
@@ -371,8 +372,8 @@ bool ScalpelEngine::showCityCutscene() {
if (finished) {
ImageFile titleImages_LondonNovember("title2.vgs", true);
- _screen->_backBuffer1.blitFrom(*_screen);
- _screen->_backBuffer2.blitFrom(*_screen);
+ _screen->_backBuffer1.SHblitFrom(*_screen);
+ _screen->_backBuffer2.SHblitFrom(*_screen);
Common::Point londonPosition;
@@ -386,19 +387,19 @@ bool ScalpelEngine::showCityCutscene() {
}
// London, England
- _screen->_backBuffer1.transBlitFrom(titleImages_LondonNovember[0], londonPosition);
+ _screen->_backBuffer1.SHtransBlitFrom(titleImages_LondonNovember[0], londonPosition);
_screen->randomTransition();
finished = _events->delay(1000, true);
// November, 1888
if (finished) {
- _screen->_backBuffer1.transBlitFrom(titleImages_LondonNovember[1], Common::Point(100, 100));
+ _screen->_backBuffer1.SHtransBlitFrom(titleImages_LondonNovember[1], Common::Point(100, 100));
_screen->randomTransition();
finished = _events->delay(5000, true);
}
// Transition out the title
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2);
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2);
_screen->randomTransition();
}
@@ -407,8 +408,8 @@ bool ScalpelEngine::showCityCutscene() {
if (finished) {
ImageFile titleImages_SherlockHolmesTitle("title.vgs", true);
- _screen->_backBuffer1.blitFrom(*_screen);
- _screen->_backBuffer2.blitFrom(*_screen);
+ _screen->_backBuffer1.SHblitFrom(*_screen);
+ _screen->_backBuffer2.SHblitFrom(*_screen);
Common::Point lostFilesPosition;
Common::Point sherlockHolmesPosition;
@@ -427,17 +428,17 @@ bool ScalpelEngine::showCityCutscene() {
}
// The Lost Files of
- _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[0], lostFilesPosition);
+ _screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[0], lostFilesPosition);
// Sherlock Holmes
- _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[1], sherlockHolmesPosition);
+ _screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[1], sherlockHolmesPosition);
// copyright
- _screen->_backBuffer1.transBlitFrom(titleImages_SherlockHolmesTitle[2], copyrightPosition);
+ _screen->_backBuffer1.SHtransBlitFrom(titleImages_SherlockHolmesTitle[2], copyrightPosition);
_screen->verticalTransition();
finished = _events->delay(4000, true);
if (finished) {
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2);
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2);
_screen->randomTransition();
finished = _events->delay(2000);
}
@@ -461,7 +462,7 @@ bool ScalpelEngine::showCityCutscene() {
// English, width 175, height 38
alleyPosition = Common::Point(72, 51);
}
- _screen->transBlitFrom(titleImages_SherlockHolmesTitle[3], alleyPosition);
+ _screen->SHtransBlitFrom(titleImages_SherlockHolmesTitle[3], alleyPosition);
_screen->fadeIn(palette, 3);
// Wait until the track got looped and the first few notes were played
@@ -537,7 +538,7 @@ bool ScalpelEngine::showAlleyCutscene() {
earlyTheFollowingMorningPosition = Common::Point(35, 52);
}
- _screen->transBlitFrom(titleImages_EarlyTheFollowingMorning[0], earlyTheFollowingMorningPosition);
+ _screen->SHtransBlitFrom(titleImages_EarlyTheFollowingMorning[0], earlyTheFollowingMorningPosition);
// fast fade-in
_screen->fadeIn(palette, 1);
@@ -641,23 +642,23 @@ bool ScalpelEngine::scrollCredits() {
delete stream;
// Save a copy of the screen background for use in drawing each credit frame
- _screen->_backBuffer1.blitFrom(*_screen);
+ _screen->_backBuffer1.SHblitFrom(*_screen);
// Loop for showing the credits
for(int idx = 0; idx < 600 && !_events->kbHit() && !shouldQuit(); ++idx) {
// Copy the entire screen background before writing text
- _screen->blitFrom(_screen->_backBuffer1);
+ _screen->SHblitFrom(_screen->_backBuffer1);
// Write the text appropriate for the next frame
if (idx < 400)
- _screen->transBlitFrom(creditsImages[0], Common::Point(10, 200 - idx), false, 0);
+ _screen->SHtransBlitFrom(creditsImages[0], Common::Point(10, 200 - idx), false, 0);
if (idx > 200)
- _screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
+ _screen->SHtransBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
// Don't show credit text on the top and bottom ten rows of the screen
- _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w(), 10));
- _screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10),
- Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h()));
+ _screen->SHblitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->width(), 10));
+ _screen->SHblitFrom(_screen->_backBuffer1, Common::Point(0, _screen->height() - 10),
+ Common::Rect(0, _screen->height() - 10, _screen->width(), _screen->height()));
_events->delay(100);
}
@@ -670,7 +671,7 @@ bool ScalpelEngine::show3DOSplash() {
// 3DO EA Splash screen
ImageFile3DO titleImage_3DOSplash("3DOSplash.cel", kImageFile3DOType_Cel);
- _screen->transBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20));
+ _screen->SHtransBlitFrom(titleImage_3DOSplash[0]._frame, Common::Point(0, -20));
bool finished = _events->delay(3000, true);
if (finished) {
@@ -706,7 +707,7 @@ bool ScalpelEngine::showCityCutscene3DO() {
_sound->playAiff("prologue/sounds/rain.aiff", 15, true);
// Fade screen to grey
- screen._backBuffer1.fill(0xCE59); // RGB565: 25, 50, 25 (grey)
+ screen._backBuffer1.clear(0xCE59); // RGB565: 25, 50, 25 (grey)
screen.fadeIntoScreen3DO(2);
}
@@ -715,16 +716,16 @@ bool ScalpelEngine::showCityCutscene3DO() {
}
if (finished) {
- screen._backBuffer1.fill(0); // fill backbuffer with black to avoid issues during fade from white
+ screen._backBuffer1.clear(0); // fill backbuffer with black to avoid issues during fade from white
finished = _animation->play3DO("26open1", true, 1, true, 2);
}
if (finished) {
- screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
// "London, England"
ImageFile3DO titleImage_London("title2a.cel", kImageFile3DOType_Cel);
- screen._backBuffer1.transBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50));
+ screen._backBuffer1.SHtransBlitFrom(titleImage_London[0]._frame, Common::Point(30, 50));
screen.fadeIntoScreen3DO(1);
finished = _events->delay(1500, true);
@@ -732,7 +733,7 @@ bool ScalpelEngine::showCityCutscene3DO() {
if (finished) {
// "November, 1888"
ImageFile3DO titleImage_November("title2b.cel", kImageFile3DOType_Cel);
- screen._backBuffer1.transBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100));
+ screen._backBuffer1.SHtransBlitFrom(titleImage_November[0]._frame, Common::Point(100, 100));
screen.fadeIntoScreen3DO(1);
finished = _music->waitUntilMSec(14700, 0, 0, 5000);
@@ -740,8 +741,8 @@ bool ScalpelEngine::showCityCutscene3DO() {
if (finished) {
// Restore screen
- _screen->_backBuffer1.blitFrom(screen._backBuffer2);
- _screen->blitFrom(screen._backBuffer1);
+ _screen->_backBuffer1.SHblitFrom(screen._backBuffer2);
+ _screen->SHblitFrom(screen._backBuffer1);
}
}
@@ -751,7 +752,7 @@ bool ScalpelEngine::showCityCutscene3DO() {
if (finished) {
// "Sherlock Holmes" (title)
ImageFile3DO titleImage_SherlockHolmesTitle("title1ab.cel", kImageFile3DOType_Cel);
- screen._backBuffer1.transBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5));
+ screen._backBuffer1.SHtransBlitFrom(titleImage_SherlockHolmesTitle[0]._frame, Common::Point(34, 5));
// Blend in
screen.fadeIntoScreen3DO(2);
@@ -761,7 +762,7 @@ bool ScalpelEngine::showCityCutscene3DO() {
if (finished) {
ImageFile3DO titleImage_Copyright("title1c.cel", kImageFile3DOType_Cel);
- screen.transBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190));
+ screen.SHtransBlitFrom(titleImage_Copyright[0]._frame, Common::Point(20, 190));
finished = _events->delay(3500, true);
}
}
@@ -780,7 +781,7 @@ bool ScalpelEngine::showCityCutscene3DO() {
if (finished) {
// "In the alley behind the Regency Theatre..."
ImageFile3DO titleImage_InTheAlley("title1d.cel", kImageFile3DOType_Cel);
- screen._backBuffer1.transBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51));
+ screen._backBuffer1.SHtransBlitFrom(titleImage_InTheAlley[0]._frame, Common::Point(72, 51));
// Fade in
screen.fadeIntoScreen3DO(4);
@@ -819,7 +820,7 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
ImageFile3DO titleImage_ScreamingVictim("scream.cel", kImageFile3DOType_Cel);
screen.clear();
- screen.transBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0));
+ screen.SHtransBlitFrom(titleImage_ScreamingVictim[0]._frame, Common::Point(0, 0));
// Play "scream.aiff"
if (_sound->_voices)
@@ -848,7 +849,7 @@ bool ScalpelEngine::showAlleyCutscene3DO() {
if (finished) {
// "Early the following morning on Baker Street..."
ImageFile3DO titleImage_EarlyTheFollowingMorning("title3.cel", kImageFile3DOType_Cel);
- screen._backBuffer1.transBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51));
+ screen._backBuffer1.SHtransBlitFrom(titleImage_EarlyTheFollowingMorning[0]._frame, Common::Point(35, 51));
// Fade in
screen.fadeIntoScreen3DO(4);
@@ -908,7 +909,7 @@ bool ScalpelEngine::showOfficeCutscene3DO() {
ImageFile3DO titleImage_CoffeeNote("note.cel", kImageFile3DOType_Cel);
_screen->clear();
- _screen->transBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0));
+ _screen->SHtransBlitFrom(titleImage_CoffeeNote[0]._frame, Common::Point(0, 0));
if (_sound->_voices) {
finished = _sound->playSound("prologue/sounds/note.aiff", WAIT_KBD_OR_FINISH);
@@ -937,7 +938,7 @@ bool ScalpelEngine::showOfficeCutscene3DO() {
// TODO: Brighten the image, possibly by doing a partial fade
// to white.
- _screen->_backBuffer2.blitFrom(_screen->_backBuffer1);
+ _screen->_backBuffer2.SHblitFrom(_screen->_backBuffer1);
for (int nr = 1; finished && nr <= 4; nr++) {
char filename[15];
@@ -945,8 +946,8 @@ bool ScalpelEngine::showOfficeCutscene3DO() {
ImageFile3DO *creditsImage = new ImageFile3DO(filename, kImageFile3DOType_Cel);
ImageFrame *creditsFrame = &(*creditsImage)[0];
for (int i = 0; finished && i < 200 + creditsFrame->_height; i++) {
- _screen->blitFrom(_screen->_backBuffer2);
- _screen->transBlitFrom(creditsFrame->_frame, Common::Point((320 - creditsFrame->_width) / 2, 200 - i));
+ _screen->SHblitFrom(_screen->_backBuffer2);
+ _screen->SHtransBlitFrom(creditsFrame->_frame, Common::Point((320 - creditsFrame->_width) / 2, 200 - i));
if (!_events->delay(70, true))
finished = false;
}
@@ -998,7 +999,7 @@ void ScalpelEngine::showLBV(const Common::String &filename) {
delete stream;
_screen->setPalette(images._palette);
- _screen->_backBuffer1.blitFrom(images[0]);
+ _screen->_backBuffer1.SHblitFrom(images[0]);
_screen->verticalTransition();
}
@@ -1156,7 +1157,7 @@ void ScalpelEngine::eraseBrumwellMirror() {
// If player is in range of the mirror, then restore background from the secondary back buffer
if (Common::Rect(70, 100, 200, 200).contains(pt)) {
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(137, 18),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(137, 18),
Common::Rect(137, 18, 184, 74));
}
}
@@ -1218,20 +1219,20 @@ void ScalpelEngine::doBrumwellMirror() {
bool flipped = people[HOLMES]._sequenceNumber == WALK_LEFT || people[HOLMES]._sequenceNumber == STOP_LEFT
|| people[HOLMES]._sequenceNumber == WALK_UPRIGHT || people[HOLMES]._sequenceNumber == STOP_UPRIGHT
|| people[HOLMES]._sequenceNumber == WALK_DOWNLEFT || people[HOLMES]._sequenceNumber == STOP_DOWNLEFT;
- _screen->_backBuffer1.transBlitFrom(imageFrame, pt + Common::Point(38, -imageFrame._frame.h - 25), flipped);
+ _screen->_backBuffer1.SHtransBlitFrom(imageFrame, pt + Common::Point(38, -imageFrame._frame.h - 25), flipped);
// Redraw the mirror borders to prevent the drawn image of Holmes from appearing outside of the mirror
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(114, 18),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(114, 18),
Common::Rect(114, 18, 137, 114));
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(137, 70),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(137, 70),
Common::Rect(137, 70, 142, 114));
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(142, 71),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(142, 71),
Common::Rect(142, 71, 159, 114));
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(159, 72),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(159, 72),
Common::Rect(159, 72, 170, 116));
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(170, 73),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(170, 73),
Common::Rect(170, 73, 184, 114));
- _screen->_backBuffer1.blitFrom(_screen->_backBuffer2, Common::Point(184, 18),
+ _screen->_backBuffer1.SHblitFrom(_screen->_backBuffer2, Common::Point(184, 18),
Common::Rect(184, 18, 212, 114));
}
}
@@ -1272,7 +1273,7 @@ void ScalpelEngine::showScummVMRestoreDialog() {
bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::Point &pos, bool isPortrait) {
Scalpel3DOScreen &screen = *(Scalpel3DOScreen *)_screen;
Scalpel3DOMovieDecoder *videoDecoder = new Scalpel3DOMovieDecoder();
- Graphics::Surface tempSurface;
+ Graphics::ManagedSurface tempSurface;
Common::Point framePos(pos.x, pos.y);
ImageFile3DO *frameImageFile = nullptr;
@@ -1307,7 +1308,7 @@ bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::P
// If we're to show the movie at half-size, we'll need a temporary intermediate surface
if (halfSize)
- tempSurface.create(width / 2, height / 2, _screen->getPixelFormat());
+ tempSurface.create(width / 2, height / 2);
while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
if (videoDecoder->needsUpdate()) {
@@ -1371,19 +1372,19 @@ bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::P
}
// Point the drawing frame to the temporary surface
- frame = &tempSurface;
+ frame = &tempSurface.rawSurface();
}
if (isPortrait && !frameShown) {
// Draw the frame (not the frame of the video, but a frame around the video) itself
- _screen->transBlitFrom(frameImage->_frame, framePos);
+ _screen->SHtransBlitFrom(frameImage->_frame, framePos);
frameShown = true;
}
if (isPortrait && !halfSize) {
screen.rawBlitFrom(*frame, Common::Point(pos.x * 2, pos.y * 2));
} else {
- _screen->blitFrom(*frame, pos);
+ _screen->SHblitFrom(*frame, pos);
}
_screen->update();
@@ -1413,9 +1414,9 @@ bool ScalpelEngine::play3doMovie(const Common::String &filename, const Common::P
}
// Restore scene
- screen._backBuffer1.blitFrom(screen._backBuffer2);
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2);
_scene->updateBackground();
- screen.slamArea(0, 0, screen.w(), CONTROLS_Y);
+ screen.slamArea(0, 0, screen.width(), CONTROLS_Y);
return !skipVideo;
}
diff --git a/engines/sherlock/scalpel/scalpel_darts.cpp b/engines/sherlock/scalpel/scalpel_darts.cpp
index 87f4566837..c5ba8032f3 100644
--- a/engines/sherlock/scalpel/scalpel_darts.cpp
+++ b/engines/sherlock/scalpel/scalpel_darts.cpp
@@ -102,7 +102,7 @@ void Darts::playDarts() {
score -= lastDart;
_roundScore += lastDart;
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1),
Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
screen.print(Common::Point(DART_INFO_X, DART_INFO_Y), DART_COL_FORE, "Dart # %d", idx + 1);
screen.print(Common::Point(DART_INFO_X, DART_INFO_Y + 10), DART_COL_FORE, "Scored %d points", lastDart);
@@ -154,7 +154,7 @@ void Darts::playDarts() {
events.wait(20);
}
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1),
Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
}
@@ -166,8 +166,8 @@ void Darts::playDarts() {
done |= _vm->shouldQuit();
if (!done) {
- screen._backBuffer2.blitFrom((*_dartImages)[0], Common::Point(0, 0));
- screen._backBuffer1.blitFrom(screen._backBuffer2);
+ screen._backBuffer2.SHblitFrom((*_dartImages)[0], Common::Point(0, 0));
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2);
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
}
} while (!done);
@@ -185,7 +185,7 @@ void Darts::loadDarts() {
_dartImages = new ImageFile("darts.vgs");
screen.setPalette(_dartImages->_palette);
- screen._backBuffer1.blitFrom((*_dartImages)[0], Common::Point(0, 0));
+ screen._backBuffer1.SHblitFrom((*_dartImages)[0], Common::Point(0, 0));
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
}
@@ -245,7 +245,7 @@ void Darts::showNames(int playerNum) {
screen.slamArea(STATUS_INFO_X + 50, STATUS_INFO_Y + 10, 81, 12);
// Make a copy of the back buffer to the secondary one
- screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
}
void Darts::showStatus(int playerNum) {
@@ -253,7 +253,7 @@ void Darts::showStatus(int playerNum) {
byte color;
// Copy scoring screen from secondary back buffer. This will erase any previously displayed status/score info
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, SHERLOCK_SCREEN_WIDTH, STATUS_INFO_Y + 48));
color = (playerNum == 0) ? PLAYER_COLOR : DART_COL_FORE;
@@ -292,7 +292,7 @@ int Darts::throwDart(int dartNum, int computer) {
if (_vm->shouldQuit())
return 0;
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_INFO_X, DART_INFO_Y - 1),
Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
screen.slamRect(Common::Rect(DART_INFO_X, DART_INFO_Y - 1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
@@ -309,9 +309,9 @@ int Darts::throwDart(int dartNum, int computer) {
// Copy the bars to the secondary back buffer so that they remain fixed at their selected values
// whilst the dart is being animated at being thrown at the board
- screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DARTBARHX - 1, DARTHORIZY - 1),
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DARTBARHX - 1, DARTHORIZY - 1),
Common::Rect(DARTBARHX - 1, DARTHORIZY - 1, DARTBARHX + DARTBARSIZE + 3, DARTHORIZY + 10));
- screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1),
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1),
Common::Rect(DARTBARVX - 1, DARTHEIGHTY - 1, DARTBARVX + 11, DARTHEIGHTY + DARTBARSIZE + 3));
// Convert height and width to relative range of -50 to 50, where 0,0 is the exact centre of the board
@@ -344,7 +344,7 @@ void Darts::drawDartThrow(const Common::Point &pt) {
// Draw the dart
Common::Point drawPos(pos.x - frame._width / 2, pos.y - frame._height);
- screen._backBuffer1.transBlitFrom(frame, drawPos);
+ screen._backBuffer1.SHtransBlitFrom(frame, drawPos);
screen.slamArea(drawPos.x, drawPos.y, frame._width, frame._height);
// Handle erasing old dart frame area
@@ -352,14 +352,14 @@ void Darts::drawDartThrow(const Common::Point &pt) {
screen.slamRect(oldDrawBounds);
oldDrawBounds = Common::Rect(drawPos.x, drawPos.y, drawPos.x + frame._width, drawPos.y + frame._height);
- screen._backBuffer1.blitFrom(screen._backBuffer2, drawPos, oldDrawBounds);
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, drawPos, oldDrawBounds);
events.wait(2);
}
// Draw dart in final "stuck to board" form
- screen._backBuffer1.transBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top));
- screen._backBuffer2.transBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top));
+ screen._backBuffer1.SHtransBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top));
+ screen._backBuffer2.SHtransBlitFrom((*_dartImages)[22], Common::Point(oldDrawBounds.left, oldDrawBounds.top));
screen.slamRect(oldDrawBounds);
}
@@ -368,8 +368,8 @@ void Darts::erasePowerBars() {
screen._backBuffer1.fillRect(Common::Rect(DARTBARHX, DARTHORIZY, DARTBARHX + DARTBARSIZE, DARTHORIZY + 10), BLACK);
screen._backBuffer1.fillRect(Common::Rect(DARTBARVX, DARTHEIGHTY, DARTBARVX + 10, DARTHEIGHTY + DARTBARSIZE), BLACK);
- screen._backBuffer1.transBlitFrom((*_dartImages)[2], Common::Point(DARTBARHX - 1, DARTHORIZY - 1));
- screen._backBuffer1.transBlitFrom((*_dartImages)[3], Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1));
+ screen._backBuffer1.SHtransBlitFrom((*_dartImages)[2], Common::Point(DARTBARHX - 1, DARTHORIZY - 1));
+ screen._backBuffer1.SHtransBlitFrom((*_dartImages)[3], Common::Point(DARTBARVX - 1, DARTHEIGHTY - 1));
screen.slamArea(DARTBARHX - 1, DARTHORIZY - 1, DARTBARSIZE + 3, 11);
screen.slamArea(DARTBARVX - 1, DARTHEIGHTY - 1, 11, DARTBARSIZE + 3);
}
@@ -398,11 +398,11 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, bool i
if (isVertical) {
screen._backBuffer1.hLine(pt.x, pt.y + DARTBARSIZE - 1 - idx, pt.x + 8, color);
- screen._backBuffer1.transBlitFrom((*_dartImages)[3], Common::Point(pt.x - 1, pt.y - 1));
+ screen._backBuffer1.SHtransBlitFrom((*_dartImages)[3], Common::Point(pt.x - 1, pt.y - 1));
screen.slamArea(pt.x, pt.y + DARTBARSIZE - 1 - idx, 8, 2);
} else {
screen._backBuffer1.vLine(pt.x + idx, pt.y, pt.y + 8, color);
- screen._backBuffer1.transBlitFrom((*_dartImages)[2], Common::Point(pt.x - 1, pt.y - 1));
+ screen._backBuffer1.SHtransBlitFrom((*_dartImages)[2], Common::Point(pt.x - 1, pt.y - 1));
screen.slamArea(pt.x + idx, pt.y, 1, 8);
}
diff --git a/engines/sherlock/scalpel/scalpel_debugger.cpp b/engines/sherlock/scalpel/scalpel_debugger.cpp
index 1495c76b43..02b39ade9b 100644
--- a/engines/sherlock/scalpel/scalpel_debugger.cpp
+++ b/engines/sherlock/scalpel/scalpel_debugger.cpp
@@ -22,10 +22,9 @@
#include "sherlock/scalpel/scalpel_debugger.h"
#include "sherlock/sherlock.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h"
-#include "audio/decoders/3do.h"
#include "audio/decoders/aiff.h"
-#include "audio/decoders/wave.h"
namespace Sherlock {
diff --git a/engines/sherlock/scalpel/scalpel_inventory.cpp b/engines/sherlock/scalpel/scalpel_inventory.cpp
index c3e20295fd..07659b41f2 100644
--- a/engines/sherlock/scalpel/scalpel_inventory.cpp
+++ b/engines/sherlock/scalpel/scalpel_inventory.cpp
@@ -72,11 +72,11 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
loadInv();
if (mode == INVENTORY_DONT_DISPLAY) {
- screen._backBuffer = &screen._backBuffer2;
+ screen.activateBackBuffer2();
}
// Draw the window background
- Surface &bb = *screen._backBuffer;
+ Surface &bb = *screen.getBackBuffer();
bb.fillRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 10), BORDER_COLOR);
bb.fillRect(Common::Rect(0, CONTROLS_Y1 + 10, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
bb.fillRect(Common::Rect(SHERLOCK_SCREEN_WIDTH - 2, CONTROLS_Y1 + 10,
@@ -109,7 +109,7 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
_invMode = (InvMode)((int)mode);
if (mode != PLAIN_INVENTORY) {
- assert(mode < sizeof(_hotkeysIndexed));
+ assert((uint)mode < sizeof(_hotkeysIndexed));
ui._oldKey = _hotkeysIndexed[mode];
} else {
ui._oldKey = -1;
@@ -128,7 +128,7 @@ void ScalpelInventory::drawInventory(InvNewMode mode) {
ui._windowOpen = true;
} else {
// Reset the screen back buffer to the first buffer now that drawing is done
- screen._backBuffer = &screen._backBuffer1;
+ screen.activateBackBuffer1();
}
assert(IS_SERRATED_SCALPEL);
@@ -196,12 +196,12 @@ void ScalpelInventory::invCommands(bool slamIt) {
void ScalpelInventory::highlight(int index, byte color) {
Screen &screen = *_vm->_screen;
- Surface &bb = *screen._backBuffer;
+ Surface &bb = *screen.getBackBuffer();
int slot = index - _invIndex;
ImageFrame &frame = (*_invShapes[slot])[0];
bb.fillRect(Common::Rect(8 + slot * 52, 165, (slot + 1) * 52, 194), color);
- bb.transBlitFrom(frame, Common::Point(6 + slot * 52 + ((47 - frame._width) / 2),
+ bb.SHtransBlitFrom(frame, Common::Point(6 + slot * 52 + ((47 - frame._width) / 2),
163 + ((33 - frame._height) / 2)));
screen.slamArea(8 + slot * 52, 165, 44, 30);
}
@@ -217,12 +217,12 @@ void ScalpelInventory::refreshInv() {
ui._infoFlag = true;
ui.clearInfo();
- screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(0, CONTROLS_Y),
Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
ui.examine();
if (!talk._talkToAbort) {
- screen._backBuffer2.blitFrom((*ui._controlPanel)[0], Common::Point(0, CONTROLS_Y));
+ screen._backBuffer2.SHblitFrom((*ui._controlPanel)[0], Common::Point(0, CONTROLS_Y));
loadInv();
}
}
@@ -264,7 +264,7 @@ void ScalpelInventory::putInv(InvSlamMode slamIt) {
// Draw the item image
ImageFrame &frame = (*_invShapes[itemNum])[0];
- bb.transBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2),
+ bb.SHtransBlitFrom(frame, Common::Point(6 + itemNum * 52 + ((47 - frame._width) / 2),
163 + ((33 - frame._height) / 2)));
}
@@ -278,9 +278,9 @@ void ScalpelInventory::putInv(InvSlamMode slamIt) {
invCommands(0);
}
else if (slamIt == SLAM_SECONDARY_BUFFER) {
- screen._backBuffer = &screen._backBuffer2;
+ screen.activateBackBuffer2();
invCommands(0);
- screen._backBuffer = &screen._backBuffer1;
+ screen.activateBackBuffer1();
}
}
diff --git a/engines/sherlock/scalpel/scalpel_journal.cpp b/engines/sherlock/scalpel/scalpel_journal.cpp
index d6f8021e5b..151d986d81 100644
--- a/engines/sherlock/scalpel/scalpel_journal.cpp
+++ b/engines/sherlock/scalpel/scalpel_journal.cpp
@@ -485,11 +485,6 @@ int ScalpelJournal::getSearchString(bool printError) {
screen.makeField(Common::Rect(12, 185, 307, 196));
- screen.fillRect(Common::Rect(12, 185, 307, 186), BUTTON_BOTTOM);
- screen.vLine(12, 185, 195, BUTTON_BOTTOM);
- screen.hLine(13, 195, 306, BUTTON_TOP);
- screen.hLine(306, 186, 195, BUTTON_TOP);
-
if (printError) {
screen.gPrint(Common::Point((SHERLOCK_SCREEN_WIDTH - screen.stringWidth(_fixedTextSearchNotFound)) / 2, 185),
INV_FOREGROUND, "%s", _fixedTextSearchNotFound.c_str());
diff --git a/engines/sherlock/scalpel/scalpel_map.cpp b/engines/sherlock/scalpel/scalpel_map.cpp
index 0924581e38..ba14b5b300 100644
--- a/engines/sherlock/scalpel/scalpel_map.cpp
+++ b/engines/sherlock/scalpel/scalpel_map.cpp
@@ -167,13 +167,13 @@ int ScalpelMap::show() {
setupSprites();
if (!IS_3DO) {
- screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
- screen._backBuffer1.blitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
- screen._backBuffer1.blitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y));
- screen._backBuffer1.blitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
} else {
- screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
- screen.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ screen.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
}
_drawMap = true;
@@ -238,12 +238,12 @@ int ScalpelMap::show() {
changed = false;
if (!IS_3DO) {
- screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
- screen._backBuffer1.blitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
- screen._backBuffer1.blitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y));
- screen._backBuffer1.blitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[1], Common::Point(-_bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[2], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, -_bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[3], Common::Point(SHERLOCK_SCREEN_WIDTH - _bigPos.x, SHERLOCK_SCREEN_HEIGHT - _bigPos.y));
} else {
- screen._backBuffer1.blitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
+ screen._backBuffer1.SHblitFrom((*bigMap)[0], Common::Point(-_bigPos.x, -_bigPos.y));
}
showPlaces();
@@ -359,7 +359,6 @@ void ScalpelMap::freeSprites() {
delete _mapCursors;
delete _shapes;
delete _iconShapes;
- _iconSave.free();
}
void ScalpelMap::showPlaces() {
@@ -376,7 +375,7 @@ void ScalpelMap::showPlaces() {
if (pt.x >= _bigPos.x && (pt.x - _bigPos.x) < SHERLOCK_SCREEN_WIDTH
&& pt.y >= _bigPos.y && (pt.y - _bigPos.y) < SHERLOCK_SCREEN_HEIGHT) {
if (_vm->readFlags(idx)) {
- screen._backBuffer1.transBlitFrom((*_iconShapes)[pt._translate],
+ screen._backBuffer1.SHtransBlitFrom((*_iconShapes)[pt._translate],
Common::Point(pt.x - _bigPos.x - 6, pt.y - _bigPos.y - 12));
}
}
@@ -388,13 +387,13 @@ void ScalpelMap::showPlaces() {
}
void ScalpelMap::saveTopLine() {
- _topLine.blitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12));
+ _topLine.SHblitFrom(_vm->_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 12));
}
void ScalpelMap::eraseTopLine() {
Screen &screen = *_vm->_screen;
- screen._backBuffer1.blitFrom(_topLine, Common::Point(0, 0));
- screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.h());
+ screen._backBuffer1.SHblitFrom(_topLine, Common::Point(0, 0));
+ screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, _topLine.height());
}
void ScalpelMap::showPlaceName(int idx, bool highlighted) {
@@ -409,7 +408,7 @@ void ScalpelMap::showPlaceName(int idx, bool highlighted) {
bool flipped = people[HOLMES]._sequenceNumber == MAP_DOWNLEFT || people[HOLMES]._sequenceNumber == MAP_LEFT
|| people[HOLMES]._sequenceNumber == MAP_UPLEFT;
- screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, _lDrawnPos, flipped);
+ screen._backBuffer1.SHtransBlitFrom(*people[HOLMES]._imageFrame, _lDrawnPos, flipped);
}
if (highlighted) {
@@ -451,9 +450,9 @@ void ScalpelMap::updateMap(bool flushScreen) {
saveIcon(people[HOLMES]._imageFrame, hPos);
if (people[HOLMES]._sequenceNumber == MAP_DOWNLEFT || people[HOLMES]._sequenceNumber == MAP_LEFT
|| people[HOLMES]._sequenceNumber == MAP_UPLEFT)
- screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, hPos, true);
+ screen._backBuffer1.SHtransBlitFrom(*people[HOLMES]._imageFrame, hPos, true);
else
- screen._backBuffer1.transBlitFrom(*people[HOLMES]._imageFrame, hPos, false);
+ screen._backBuffer1.SHtransBlitFrom(*people[HOLMES]._imageFrame, hPos, false);
if (flushScreen) {
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
@@ -553,8 +552,8 @@ void ScalpelMap::saveIcon(ImageFrame *src, const Common::Point &pt) {
return;
}
- assert(size.x <= _iconSave.w() && size.y <= _iconSave.h());
- _iconSave.blitFrom(screen._backBuffer1, Common::Point(0, 0),
+ assert(size.x <= _iconSave.width() && size.y <= _iconSave.height());
+ _iconSave.SHblitFrom(screen._backBuffer1, Common::Point(0, 0),
Common::Rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y));
_savedPos = pos;
_savedSize = size;
@@ -565,7 +564,7 @@ void ScalpelMap::restoreIcon() {
if (_savedPos.x >= 0 && _savedPos.y >= 0 && _savedPos.x <= SHERLOCK_SCREEN_WIDTH
&& _savedPos.y < SHERLOCK_SCREEN_HEIGHT)
- screen._backBuffer1.blitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y));
+ screen._backBuffer1.SHblitFrom(_iconSave, _savedPos, Common::Rect(0, 0, _savedSize.x, _savedSize.y));
}
void ScalpelMap::highlightIcon(const Common::Point &pt) {
diff --git a/engines/sherlock/scalpel/scalpel_scene.cpp b/engines/sherlock/scalpel/scalpel_scene.cpp
index b62703e0fb..11fb807c3b 100644
--- a/engines/sherlock/scalpel/scalpel_scene.cpp
+++ b/engines/sherlock/scalpel/scalpel_scene.cpp
@@ -71,26 +71,26 @@ void ScalpelScene::drawAllShapes() {
// Draw all active shapes which are behind the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE && _bgShapes[idx]._misc == BEHIND)
- screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED);
}
// Draw all canimations which are behind the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
if (_canimShapes[idx]->_type == ACTIVE_BG_SHAPE && _canimShapes[idx]->_misc == BEHIND)
- screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame,
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame,
_canimShapes[idx]->_position, _canimShapes[idx]->_flags & OBJ_FLIPPED);
}
// Draw all active shapes which are normal and behind the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE && _bgShapes[idx]._misc == NORMAL_BEHIND)
- screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position, _bgShapes[idx]._flags & OBJ_FLIPPED);
}
// Draw all canimations which are normal and behind the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
if (_canimShapes[idx]->_type == ACTIVE_BG_SHAPE && _canimShapes[idx]->_misc == NORMAL_BEHIND)
- screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
_canimShapes[idx]->_flags & OBJ_FLIPPED);
}
@@ -103,7 +103,7 @@ void ScalpelScene::drawAllShapes() {
p._sequenceNumber == WALK_UPLEFT || p._sequenceNumber == STOP_UPLEFT ||
p._sequenceNumber == WALK_DOWNRIGHT || p._sequenceNumber == STOP_DOWNRIGHT);
- screen._backBuffer->transBlitFrom(*p._imageFrame, Common::Point(p._position.x / FIXED_INT_MULTIPLIER,
+ screen.getBackBuffer()->SHtransBlitFrom(*p._imageFrame, Common::Point(p._position.x / FIXED_INT_MULTIPLIER,
p._position.y / FIXED_INT_MULTIPLIER - p.frameHeight()), flipped);
}
}
@@ -112,7 +112,7 @@ void ScalpelScene::drawAllShapes() {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) &&
_bgShapes[idx]._misc == NORMAL_FORWARD)
- screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
+ screen.getBackBuffer()->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
_bgShapes[idx]._flags & OBJ_FLIPPED);
}
@@ -120,7 +120,7 @@ void ScalpelScene::drawAllShapes() {
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
if ((_canimShapes[idx]->_type == ACTIVE_BG_SHAPE || _canimShapes[idx]->_type == STATIC_BG_SHAPE) &&
_canimShapes[idx]->_misc == NORMAL_FORWARD)
- screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
_canimShapes[idx]->_flags & OBJ_FLIPPED);
}
@@ -132,7 +132,7 @@ void ScalpelScene::drawAllShapes() {
if ((_bgShapes[idx]._type == ACTIVE_BG_SHAPE || _bgShapes[idx]._type == STATIC_BG_SHAPE) &&
_bgShapes[idx]._misc == FORWARD)
- screen._backBuffer->transBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
+ screen.getBackBuffer()->SHtransBlitFrom(*_bgShapes[idx]._imageFrame, _bgShapes[idx]._position,
_bgShapes[idx]._flags & OBJ_FLIPPED);
}
@@ -140,7 +140,7 @@ void ScalpelScene::drawAllShapes() {
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
if ((_canimShapes[idx]->_type == ACTIVE_BG_SHAPE || _canimShapes[idx]->_type == STATIC_BG_SHAPE) &&
_canimShapes[idx]->_misc == FORWARD)
- screen._backBuffer->transBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
+ screen.getBackBuffer()->SHtransBlitFrom(*_canimShapes[idx]->_imageFrame, _canimShapes[idx]->_position,
_canimShapes[idx]->_flags & OBJ_FLIPPED);
}
@@ -242,7 +242,7 @@ void ScalpelScene::doBgAnim() {
if (people[HOLMES]._type == CHARACTER)
screen.restoreBackground(bounds);
else if (people[HOLMES]._type == REMOVE)
- screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds);
+ screen.getBackBuffer()->SHblitFrom(screen._backBuffer2, pt, bounds);
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
@@ -261,7 +261,7 @@ void ScalpelScene::doBgAnim() {
Object &o = _bgShapes[idx];
if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) {
// Restore screen area
- screen._backBuffer->blitFrom(screen._backBuffer2, o._position,
+ screen.getBackBuffer()->SHblitFrom(screen._backBuffer2, o._position,
Common::Rect(o._position.x, o._position.y,
o._position.x + o._noShapeSize.x, o._position.y + o._noShapeSize.y));
@@ -309,14 +309,14 @@ void ScalpelScene::doBgAnim() {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND)
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw all canimations which are behind the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = *_canimShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) {
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
@@ -324,14 +324,14 @@ void ScalpelScene::doBgAnim() {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND)
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw all canimations which are NORMAL and behind the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = *_canimShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) {
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
@@ -344,7 +344,7 @@ void ScalpelScene::doBgAnim() {
bool flipped = people[HOLMES]._sequenceNumber == WALK_LEFT || people[HOLMES]._sequenceNumber == STOP_LEFT ||
people[HOLMES]._sequenceNumber == WALK_UPLEFT || people[HOLMES]._sequenceNumber == STOP_UPLEFT ||
people[HOLMES]._sequenceNumber == WALK_DOWNRIGHT || people[HOLMES]._sequenceNumber == STOP_DOWNRIGHT;
- screen._backBuffer->transBlitFrom(*people[HOLMES]._imageFrame,
+ screen.getBackBuffer()->SHtransBlitFrom(*people[HOLMES]._imageFrame,
Common::Point(tempX, people[HOLMES]._position.y / FIXED_INT_MULTIPLIER - people[HOLMES]._imageFrame->_frame.h), flipped);
}
@@ -352,14 +352,14 @@ void ScalpelScene::doBgAnim() {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD)
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw all static and active canimations that are NORMAL and are in front of the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = *_canimShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) {
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
@@ -367,19 +367,19 @@ void ScalpelScene::doBgAnim() {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD)
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw any active portrait
if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
- screen._backBuffer->transBlitFrom(*people._portrait._imageFrame,
+ screen.getBackBuffer()->SHtransBlitFrom(*people._portrait._imageFrame,
people._portrait._position, people._portrait._flags & OBJ_FLIPPED);
// Draw all static and active canimations that are in front of the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = *_canimShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) {
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
@@ -387,7 +387,7 @@ void ScalpelScene::doBgAnim() {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0)
- screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
+ screen.getBackBuffer()->SHtransBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Bring the newly built picture to the screen
diff --git a/engines/sherlock/scalpel/scalpel_screen.cpp b/engines/sherlock/scalpel/scalpel_screen.cpp
index 197a2a2634..15e8436be6 100644
--- a/engines/sherlock/scalpel/scalpel_screen.cpp
+++ b/engines/sherlock/scalpel/scalpel_screen.cpp
@@ -28,12 +28,15 @@ namespace Sherlock {
namespace Scalpel {
ScalpelScreen::ScalpelScreen(SherlockEngine *vm) : Screen(vm) {
+ _backBuffer1.create(320, 200);
+ _backBuffer2.create(320, 200);
+ activateBackBuffer1();
}
void ScalpelScreen::makeButton(const Common::Rect &bounds, int textX,
const Common::String &buttonText, bool textContainsHotkey) {
- Surface &bb = *_backBuffer;
+ Surface &bb = _backBuffer;
bb.fillRect(Common::Rect(bounds.left, bounds.top, bounds.right, bounds.top + 1), BUTTON_TOP);
bb.fillRect(Common::Rect(bounds.left, bounds.top, bounds.left + 1, bounds.bottom), BUTTON_TOP);
bb.fillRect(Common::Rect(bounds.right - 1, bounds.top, bounds.right, bounds.bottom), BUTTON_BOTTOM);
@@ -103,273 +106,24 @@ void ScalpelScreen::buttonPrint(const Common::Point &pt, uint color, bool slamIt
}
void ScalpelScreen::makePanel(const Common::Rect &r) {
- _backBuffer->fillRect(r, BUTTON_MIDDLE);
- _backBuffer->hLine(r.left, r.top, r.right - 2, BUTTON_TOP);
- _backBuffer->hLine(r.left + 1, r.top + 1, r.right - 3, BUTTON_TOP);
- _backBuffer->vLine(r.left, r.top, r.bottom - 1, BUTTON_TOP);
- _backBuffer->vLine(r.left + 1, r.top + 1, r.bottom - 2, BUTTON_TOP);
-
- _backBuffer->vLine(r.right - 1, r.top, r.bottom - 1, BUTTON_BOTTOM);
- _backBuffer->vLine(r.right - 2, r.top + 1, r.bottom - 2, BUTTON_BOTTOM);
- _backBuffer->hLine(r.left, r.bottom - 1, r.right - 1, BUTTON_BOTTOM);
- _backBuffer->hLine(r.left + 1, r.bottom - 2, r.right - 1, BUTTON_BOTTOM);
+ _backBuffer.fillRect(r, BUTTON_MIDDLE);
+ _backBuffer.hLine(r.left, r.top, r.right - 2, BUTTON_TOP);
+ _backBuffer.hLine(r.left + 1, r.top + 1, r.right - 3, BUTTON_TOP);
+ _backBuffer.vLine(r.left, r.top, r.bottom - 1, BUTTON_TOP);
+ _backBuffer.vLine(r.left + 1, r.top + 1, r.bottom - 2, BUTTON_TOP);
+
+ _backBuffer.vLine(r.right - 1, r.top, r.bottom - 1, BUTTON_BOTTOM);
+ _backBuffer.vLine(r.right - 2, r.top + 1, r.bottom - 2, BUTTON_BOTTOM);
+ _backBuffer.hLine(r.left, r.bottom - 1, r.right - 1, BUTTON_BOTTOM);
+ _backBuffer.hLine(r.left + 1, r.bottom - 2, r.right - 1, BUTTON_BOTTOM);
}
void ScalpelScreen::makeField(const Common::Rect &r) {
- _backBuffer->fillRect(r, BUTTON_MIDDLE);
- _backBuffer->hLine(r.left, r.top, r.right - 1, BUTTON_BOTTOM);
- _backBuffer->hLine(r.left + 1, r.bottom - 1, r.right - 1, BUTTON_TOP);
- _backBuffer->vLine(r.left, r.top + 1, r.bottom - 1, BUTTON_BOTTOM);
- _backBuffer->vLine(r.right - 1, r.top + 1, r.bottom - 2, BUTTON_TOP);
-}
-
-/*----------------------------------------------------------------*/
-
-void Scalpel3DOScreen::blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) {
- if (!_vm->_isScreenDoubled) {
- ScalpelScreen::blitFrom(src, pt, srcBounds);
- return;
- }
-
- Common::Rect srcRect = srcBounds;
- Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height());
-
- if (!srcRect.isValidRect() || !clip(srcRect, destRect))
- return;
-
- // Add dirty area remapped to the 640x200 surface
- addDirtyRect(Common::Rect(destRect.left * 2, destRect.top * 2, destRect.right * 2, destRect.bottom * 2));
-
- // Transfer the area, doubling each pixel
- for (int yp = 0; yp < srcRect.height(); ++yp) {
- const uint16 *srcP = (const uint16 *)src.getBasePtr(srcRect.left, srcRect.top + yp);
- uint16 *destP = (uint16 *)getBasePtr(destRect.left * 2, (destRect.top + yp) * 2);
-
- for (int xp = srcRect.left; xp < srcRect.right; ++xp, ++srcP, destP += 2) {
- *destP = *srcP;
- *(destP + 1) = *srcP;
- *(destP + 640) = *srcP;
- *(destP + 640 + 1) = *srcP;
- }
- }
-}
-
-void Scalpel3DOScreen::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt,
- bool flipped, int overrideColor) {
- if (!_vm->_isScreenDoubled) {
- ScalpelScreen::transBlitFromUnscaled(src, pt, flipped, overrideColor);
- return;
- }
-
- Common::Rect drawRect(0, 0, src.w, src.h);
- Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h);
-
- // Clip the display area to on-screen
- if (!clip(drawRect, destRect))
- // It's completely off-screen
- return;
-
- if (flipped)
- drawRect = Common::Rect(src.w - drawRect.right, src.h - drawRect.bottom,
- src.w - drawRect.left, src.h - drawRect.top);
-
- Common::Point destPt(destRect.left, destRect.top);
- addDirtyRect(Common::Rect(destPt.x * 2, destPt.y * 2, (destPt.x + drawRect.width()) * 2,
- (destPt.y + drawRect.height()) * 2));
-
- assert(src.format.bytesPerPixel == 2 && _surface.format.bytesPerPixel == 2);
-
- for (int yp = 0; yp < drawRect.height(); ++yp) {
- const uint16 *srcP = (const uint16 *)src.getBasePtr(
- flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp);
- uint16 *destP = (uint16 *)getBasePtr(destPt.x * 2, (destPt.y + yp) * 2);
-
- for (int xp = 0; xp < drawRect.width(); ++xp, destP += 2) {
- // RGB 0, 0, 0 -> transparent on 3DO
- if (*srcP) {
- *destP = *srcP;
- *(destP + 1) = *srcP;
- *(destP + 640) = *srcP;
- *(destP + 640 + 1) = *srcP;
- }
-
- srcP = flipped ? srcP - 1 : srcP + 1;
- }
- }
-}
-
-void Scalpel3DOScreen::fillRect(const Common::Rect &r, uint color) {
- if (_vm->_isScreenDoubled)
- ScalpelScreen::fillRect(Common::Rect(r.left * 2, r.top * 2, r.right * 2, r.bottom * 2), color);
- else
- ScalpelScreen::fillRect(r, color);
-}
-
-void Scalpel3DOScreen::fadeIntoScreen3DO(int speed) {
- Events &events = *_vm->_events;
- uint16 *currentScreenBasePtr = (uint16 *)getPixels();
- uint16 *targetScreenBasePtr = (uint16 *)_backBuffer->getPixels();
- uint16 currentScreenPixel = 0;
- uint16 targetScreenPixel = 0;
-
- uint16 currentScreenPixelRed = 0;
- uint16 currentScreenPixelGreen = 0;
- uint16 currentScreenPixelBlue = 0;
-
- uint16 targetScreenPixelRed = 0;
- uint16 targetScreenPixelGreen = 0;
- uint16 targetScreenPixelBlue = 0;
-
- uint16 screenWidth = SHERLOCK_SCREEN_WIDTH;
- uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT;
- uint16 screenX = 0;
- uint16 screenY = 0;
- uint16 pixelsChanged = 0;
-
- clearDirtyRects();
-
- do {
- pixelsChanged = 0;
- uint16 *currentScreenPtr = currentScreenBasePtr;
- uint16 *targetScreenPtr = targetScreenBasePtr;
-
- for (screenY = 0; screenY < screenHeight; screenY++) {
- for (screenX = 0; screenX < screenWidth; screenX++) {
- currentScreenPixel = *currentScreenPtr;
- targetScreenPixel = *targetScreenPtr;
-
- if (currentScreenPixel != targetScreenPixel) {
- // pixel doesn't match, adjust accordingly
- currentScreenPixelRed = currentScreenPixel & 0xF800;
- currentScreenPixelGreen = currentScreenPixel & 0x07E0;
- currentScreenPixelBlue = currentScreenPixel & 0x001F;
- targetScreenPixelRed = targetScreenPixel & 0xF800;
- targetScreenPixelGreen = targetScreenPixel & 0x07E0;
- targetScreenPixelBlue = targetScreenPixel & 0x001F;
-
- if (currentScreenPixelRed != targetScreenPixelRed) {
- if (currentScreenPixelRed < targetScreenPixelRed) {
- currentScreenPixelRed += 0x0800;
- } else {
- currentScreenPixelRed -= 0x0800;
- }
- }
- if (currentScreenPixelGreen != targetScreenPixelGreen) {
- // Adjust +2/-2 because we are running RGB555 at RGB565
- if (currentScreenPixelGreen < targetScreenPixelGreen) {
- currentScreenPixelGreen += 0x0040;
- } else {
- currentScreenPixelGreen -= 0x0040;
- }
- }
- if (currentScreenPixelBlue != targetScreenPixelBlue) {
- if (currentScreenPixelBlue < targetScreenPixelBlue) {
- currentScreenPixelBlue += 0x0001;
- } else {
- currentScreenPixelBlue -= 0x0001;
- }
- }
-
- uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
- *currentScreenPtr = v;
- if (_vm->_isScreenDoubled) {
- *(currentScreenPtr + 1) = v;
- *(currentScreenPtr + 640) = v;
- *(currentScreenPtr + 640 + 1) = v;
- }
-
- pixelsChanged++;
- }
-
- currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1;
- targetScreenPtr++;
- }
-
- if (_vm->_isScreenDoubled)
- currentScreenPtr += 640;
- }
-
- // Too much considered dirty at the moment
- if (_vm->_isScreenDoubled)
- addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2));
- else
- addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight));
-
- events.pollEvents();
- events.delay(10 * speed);
- } while ((pixelsChanged) && (!_vm->shouldQuit()));
-}
-
-void Scalpel3DOScreen::blitFrom3DOcolorLimit(uint16 limitColor) {
- uint16 *currentScreenPtr = (uint16 *)getPixels();
- uint16 *targetScreenPtr = (uint16 *)_backBuffer->getPixels();
- uint16 currentScreenPixel = 0;
-
- uint16 screenWidth = SHERLOCK_SCREEN_WIDTH;
- uint16 screenHeight = SHERLOCK_SCREEN_HEIGHT;
- uint16 screenX = 0;
- uint16 screenY = 0;
-
- uint16 currentScreenPixelRed = 0;
- uint16 currentScreenPixelGreen = 0;
- uint16 currentScreenPixelBlue = 0;
-
- uint16 limitPixelRed = limitColor & 0xF800;
- uint16 limitPixelGreen = limitColor & 0x07E0;
- uint16 limitPixelBlue = limitColor & 0x001F;
-
- for (screenY = 0; screenY < screenHeight; screenY++) {
- for (screenX = 0; screenX < screenWidth; screenX++) {
- currentScreenPixel = *targetScreenPtr;
-
- currentScreenPixelRed = currentScreenPixel & 0xF800;
- currentScreenPixelGreen = currentScreenPixel & 0x07E0;
- currentScreenPixelBlue = currentScreenPixel & 0x001F;
-
- if (currentScreenPixelRed < limitPixelRed)
- currentScreenPixelRed = limitPixelRed;
- if (currentScreenPixelGreen < limitPixelGreen)
- currentScreenPixelGreen = limitPixelGreen;
- if (currentScreenPixelBlue < limitPixelBlue)
- currentScreenPixelBlue = limitPixelBlue;
-
- uint16 v = currentScreenPixelRed | currentScreenPixelGreen | currentScreenPixelBlue;
- *currentScreenPtr = v;
- if (_vm->_isScreenDoubled) {
- *(currentScreenPtr + 1) = v;
- *(currentScreenPtr + 640) = v;
- *(currentScreenPtr + 640 + 1) = v;
- }
-
- currentScreenPtr += _vm->_isScreenDoubled ? 2 : 1;
- targetScreenPtr++;
- }
-
- if (_vm->_isScreenDoubled)
- currentScreenPtr += 640;
- }
-
- // Too much considered dirty at the moment
- if (_vm->_isScreenDoubled)
- addDirtyRect(Common::Rect(0, 0, screenWidth * 2, screenHeight * 2));
- else
- addDirtyRect(Common::Rect(0, 0, screenWidth, screenHeight));
-}
-
-uint16 Scalpel3DOScreen::w() const {
- return _vm->_isScreenDoubled ? _surface.w / 2 : _surface.w;
-}
-
-uint16 Scalpel3DOScreen::h() const {
- return _vm->_isScreenDoubled ? _surface.h / 2 : _surface.h;
-}
-
-void Scalpel3DOScreen::rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt) {
- Common::Rect srcRect(0, 0, src.w, src.h);
- Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h);
-
- addDirtyRect(destRect);
- _surface.copyRectToSurface(src, destRect.left, destRect.top, srcRect);
+ _backBuffer.fillRect(r, BUTTON_MIDDLE);
+ _backBuffer.hLine(r.left, r.top, r.right - 1, BUTTON_BOTTOM);
+ _backBuffer.hLine(r.left + 1, r.bottom - 1, r.right - 1, BUTTON_TOP);
+ _backBuffer.vLine(r.left, r.top + 1, r.bottom - 1, BUTTON_BOTTOM);
+ _backBuffer.vLine(r.right - 1, r.top + 1, r.bottom - 2, BUTTON_TOP);
}
} // End of namespace Scalpel
diff --git a/engines/sherlock/scalpel/scalpel_screen.h b/engines/sherlock/scalpel/scalpel_screen.h
index cee33b8c6c..d9be29c8b2 100644
--- a/engines/sherlock/scalpel/scalpel_screen.h
+++ b/engines/sherlock/scalpel/scalpel_screen.h
@@ -61,44 +61,6 @@ public:
void makeField(const Common::Rect &r);
};
-class Scalpel3DOScreen : public ScalpelScreen {
-protected:
- /**
- * Draws a sub-section of a surface at a given position within this surface
- * Overriden for the 3DO to automatically double the size of everything to the underlying 640x400 surface
- */
- virtual void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
-
- /**
- * Draws a surface at a given position within this surface with transparency
- */
- virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped,
- int overrideColor);
-public:
- Scalpel3DOScreen(SherlockEngine *vm) : ScalpelScreen(vm) {}
- virtual ~Scalpel3DOScreen() {}
-
- /**
- * Draws a sub-section of a surface at a given position within this surface
- */
- void rawBlitFrom(const Graphics::Surface &src, const Common::Point &pt);
-
- /**
- * Fade backbuffer 1 into screen (3DO RGB!)
- */
- void fadeIntoScreen3DO(int speed);
-
- void blitFrom3DOcolorLimit(uint16 color);
-
- /**
- * Fill a given area of the surface with a given color
- */
- virtual void fillRect(const Common::Rect &r, uint color);
-
- virtual uint16 w() const;
- virtual uint16 h() const;
-};
-
} // End of namespace Scalpel
} // End of namespace Sherlock
diff --git a/engines/sherlock/scalpel/scalpel_talk.cpp b/engines/sherlock/scalpel/scalpel_talk.cpp
index b6e9482e3c..ff38c07537 100644
--- a/engines/sherlock/scalpel/scalpel_talk.cpp
+++ b/engines/sherlock/scalpel/scalpel_talk.cpp
@@ -684,7 +684,7 @@ Common::Point ScalpelTalk::get3doPortraitPosition() const {
void ScalpelTalk::drawInterface() {
ScalpelScreen &screen = *(ScalpelScreen *)_vm->_screen;
- Surface &bb = *screen._backBuffer;
+ Surface &bb = *screen.getBackBuffer();
bb.fillRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y1 + 10), BORDER_COLOR);
bb.fillRect(Common::Rect(0, CONTROLS_Y + 10, 2, SHERLOCK_SCREEN_HEIGHT), BORDER_COLOR);
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.cpp b/engines/sherlock/scalpel/scalpel_user_interface.cpp
index 7ac8d0d5cf..8dae24ecd4 100644
--- a/engines/sherlock/scalpel/scalpel_user_interface.cpp
+++ b/engines/sherlock/scalpel/scalpel_user_interface.cpp
@@ -148,23 +148,24 @@ void ScalpelUserInterface::reset() {
void ScalpelUserInterface::drawInterface(int bufferNum) {
Screen &screen = *_vm->_screen;
- const ImageFrame &src = (*_controlPanel)[0];
+ const Graphics::Surface &src = (*_controlPanel)[0]._frame;
int16 x = (!IS_3DO) ? 0 : UI_OFFSET_3DO;
if (bufferNum & 1) {
if (IS_3DO)
screen._backBuffer1.fillRect(Common::Rect(0, CONTROLS_Y,
SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BLACK);
- screen._backBuffer1.transBlitFrom(src, Common::Point(x, CONTROLS_Y));
+ screen._backBuffer1.SHtransBlitFrom(src, Common::Point(x, CONTROLS_Y));
}
if (bufferNum & 2) {
if (IS_3DO)
screen._backBuffer2.fillRect(Common::Rect(0, CONTROLS_Y,
SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), BLACK);
- screen._backBuffer2.transBlitFrom(src, Common::Point(x, CONTROLS_Y));
+ screen._backBuffer2.SHtransBlitFrom(src, Common::Point(x, CONTROLS_Y));
}
if (bufferNum == 3)
- screen._backBuffer2.fillRect(0, INFO_LINE, SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10, INFO_BLACK);
+ screen._backBuffer2.SHfillRect(Common::Rect(0, INFO_LINE,
+ SHERLOCK_SCREEN_WIDTH, INFO_LINE + 10), INFO_BLACK);
}
void ScalpelUserInterface::handleInput() {
@@ -426,7 +427,7 @@ void ScalpelUserInterface::depressButton(int num) {
offsetButton3DO(pt, num);
ImageFrame &frame = (*_controls)[num];
- screen._backBuffer1.transBlitFrom(frame, pt);
+ screen._backBuffer1.SHtransBlitFrom(frame, pt);
screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
}
@@ -442,7 +443,7 @@ void ScalpelUserInterface::restoreButton(int num) {
events.setCursor(ARROW);
// Restore the UI on the back buffer
- screen._backBuffer1.blitFrom(screen._backBuffer2, pt,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, pt,
Common::Rect(pt.x, pt.y, pt.x + 90, pt.y + 19));
screen.slamArea(pt.x, pt.y, pt.x + frame.w, pt.y + frame.h);
@@ -489,7 +490,7 @@ void ScalpelUserInterface::toggleButton(uint16 num) {
ImageFrame &frame = (*_controls)[num];
Common::Point pt(MENU_POINTS[num][0], MENU_POINTS[num][1]);
offsetButton3DO(pt, num);
- screen._backBuffer1.transBlitFrom(frame, pt);
+ screen._backBuffer1.SHtransBlitFrom(frame, pt);
screen.slamArea(pt.x, pt.y, pt.x + frame._width, pt.y + frame._height);
}
} else {
@@ -1272,7 +1273,7 @@ void ScalpelUserInterface::doLookControl() {
// Need to close the window and depress the Look button
Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]);
offsetButton3DO(pt, 0);
- screen._backBuffer2.blitFrom((*_controls)[0], pt);
+ screen._backBuffer2.SHblitFrom((*_controls)[0], pt);
banishWindow(true);
_windowBounds.top = CONTROLS_Y1;
@@ -1296,14 +1297,14 @@ void ScalpelUserInterface::doLookControl() {
// Looking at an inventory object
// Backup the user interface
Surface tempSurface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - CONTROLS_Y1);
- tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0),
+ tempSurface.SHblitFrom(screen._backBuffer2, Common::Point(0, 0),
Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
inv.drawInventory(INVENTORY_DONT_DISPLAY);
banishWindow(true);
// Restore the ui
- screen._backBuffer2.blitFrom(tempSurface, Common::Point(0, CONTROLS_Y1));
+ screen._backBuffer2.SHblitFrom(tempSurface, Common::Point(0, CONTROLS_Y1));
_windowBounds.top = CONTROLS_Y1;
_key = _oldKey = _hotkeyLook;
@@ -1887,7 +1888,7 @@ void ScalpelUserInterface::journalControl() {
// Reset the palette
screen.setPalette(screen._cMap);
- screen._backBuffer1.blitFrom(screen._backBuffer2);
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2);
scene.updateBackground();
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
}
@@ -1921,9 +1922,9 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first
Common::Point pt(MENU_POINTS[0][0], MENU_POINTS[0][1]);
offsetButton3DO(pt, 0);
- tempSurface.blitFrom(screen._backBuffer2, Common::Point(0, 0),
- Common::Rect(pt.x, pt.y, pt.x + tempSurface.w(), pt.y + tempSurface.h()));
- screen._backBuffer2.transBlitFrom((*_controls)[0], pt);
+ tempSurface.SHblitFrom(screen._backBuffer2, Common::Point(0, 0),
+ Common::Rect(pt.x, pt.y, pt.x + tempSurface.width(), pt.y + tempSurface.height()));
+ screen._backBuffer2.SHtransBlitFrom((*_controls)[0], pt);
banishWindow(1);
events.setCursor(MAGNIFY);
@@ -1933,7 +1934,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first
_menuMode = LOOK_MODE;
events.clearEvents();
- screen._backBuffer2.blitFrom(tempSurface, pt);
+ screen._backBuffer2.SHblitFrom(tempSurface, pt);
} else {
events.setCursor(ARROW);
banishWindow(true);
@@ -1967,7 +1968,7 @@ void ScalpelUserInterface::printObjectDesc(const Common::String &str, bool first
return;
}
- Surface &bb = *screen._backBuffer;
+ Surface &bb = *screen.getBackBuffer();
if (firstTime) {
// Only draw the border on the first call
_infoFlag = true;
@@ -2071,9 +2072,9 @@ void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp)
if (slideUp) {
// Gradually slide up the display of the window
- for (int idx = 1; idx <= bgSurface.h(); idx += 2) {
- screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - idx),
- Common::Rect(0, 0, bgSurface.w(), idx));
+ for (int idx = 1; idx <= bgSurface.height(); idx += 2) {
+ screen.getBackBuffer()->SHblitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - idx),
+ Common::Rect(0, 0, bgSurface.width(), idx));
screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - idx,
SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
@@ -2081,21 +2082,21 @@ void ScalpelUserInterface::summonWindow(const Surface &bgSurface, bool slideUp)
}
} else {
// Gradually slide down the display of the window
- for (int idx = 1; idx <= bgSurface.h(); idx += 2) {
- screen._backBuffer->blitFrom(bgSurface,
- Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()),
- Common::Rect(0, bgSurface.h() - idx, bgSurface.w(), bgSurface.h()));
- screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(),
- SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - bgSurface.h() + idx));
+ for (int idx = 1; idx <= bgSurface.height(); idx += 2) {
+ screen.getBackBuffer()->SHblitFrom(bgSurface,
+ Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height()),
+ Common::Rect(0, bgSurface.height() - idx, bgSurface.width(), bgSurface.height()));
+ screen.slamRect(Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height(),
+ SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - bgSurface.height() + idx));
events.delay(10);
}
}
// Final display of the entire window
- screen._backBuffer->blitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h()),
- Common::Rect(0, 0, bgSurface.w(), bgSurface.h()));
- screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.h(), bgSurface.w(), bgSurface.h());
+ screen.getBackBuffer()->SHblitFrom(bgSurface, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height()),
+ Common::Rect(0, 0, bgSurface.width(), bgSurface.height()));
+ screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - bgSurface.height(), bgSurface.width(), bgSurface.height());
_windowOpen = true;
}
@@ -2106,10 +2107,10 @@ void ScalpelUserInterface::summonWindow(bool slideUp, int height) {
// Extract the window that's been drawn on the back buffer
Surface tempSurface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT - height);
Common::Rect r(0, height, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
- tempSurface.blitFrom(screen._backBuffer1, Common::Point(0, 0), r);
+ tempSurface.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), r);
// Remove drawn window with original user interface
- screen._backBuffer1.blitFrom(screen._backBuffer2,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2,
Common::Point(0, height), r);
// Display the window gradually on-screen
@@ -2133,7 +2134,7 @@ void ScalpelUserInterface::banishWindow(bool slideUp) {
Common::copy_backward(pSrc, pSrcEnd, pDest);
// Restore lines from the ui in the secondary back buffer
- screen._backBuffer1.blitFrom(screen._backBuffer2,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2,
Common::Point(0, CONTROLS_Y),
Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, CONTROLS_Y + idx));
@@ -2143,14 +2144,14 @@ void ScalpelUserInterface::banishWindow(bool slideUp) {
}
// Restore final two old lines
- screen._backBuffer1.blitFrom(screen._backBuffer2,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2,
Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 2),
Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 2,
SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
screen.slamArea(0, SHERLOCK_SCREEN_HEIGHT - 2, SHERLOCK_SCREEN_WIDTH, 2);
} else {
// Restore old area to completely erase window
- screen._backBuffer1.blitFrom(screen._backBuffer2,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2,
Common::Point(0, CONTROLS_Y),
Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
screen.slamRect(Common::Rect(0, CONTROLS_Y, SHERLOCK_SCREEN_WIDTH,
@@ -2170,7 +2171,7 @@ void ScalpelUserInterface::banishWindow(bool slideUp) {
}
// Show entire final area
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y1),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(0, CONTROLS_Y1),
Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
screen.slamRect(Common::Rect(0, CONTROLS_Y1, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
}
diff --git a/engines/sherlock/scalpel/scalpel_user_interface.h b/engines/sherlock/scalpel/scalpel_user_interface.h
index c0b8672a87..cc3aafff65 100644
--- a/engines/sherlock/scalpel/scalpel_user_interface.h
+++ b/engines/sherlock/scalpel/scalpel_user_interface.h
@@ -58,7 +58,7 @@ class Settings;
class ScalpelUserInterface: public UserInterface {
friend class Settings;
- friend class Talk;
+ friend class Sherlock::Talk;
private:
char _keyPress;
int _lookHelp;
diff --git a/engines/sherlock/scalpel/tsage/logo.cpp b/engines/sherlock/scalpel/tsage/logo.cpp
index 273d26df74..a885057f35 100644
--- a/engines/sherlock/scalpel/tsage/logo.cpp
+++ b/engines/sherlock/scalpel/tsage/logo.cpp
@@ -217,7 +217,7 @@ void Object::erase() {
Screen &screen = *_vm->_screen;
if (_visage.isLoaded() && !_oldBounds.isEmpty())
- screen.blitFrom(screen._backBuffer1, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds);
+ screen.SHblitFrom(screen._backBuffer1, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds);
}
void Object::update() {
@@ -246,9 +246,9 @@ void Object::update() {
_visage.getFrame(s, _frame);
// Display the frame
- _oldBounds = Common::Rect(_position.x, _position.y, _position.x + s.w(), _position.y + s.h());
+ _oldBounds = Common::Rect(_position.x, _position.y, _position.x + s.width(), _position.y + s.height());
_oldBounds.translate(-s._centroid.x, -s._centroid.y);
- screen.transBlitFrom(s, Common::Point(_oldBounds.left, _oldBounds.top));
+ screen.SHtransBlitFrom(s, Common::Point(_oldBounds.left, _oldBounds.top));
}
}
@@ -652,7 +652,7 @@ void Logo::loadBackground() {
screen.setPalette(palette);
// Copy the surface to the screen
- screen.blitFrom(screen._backBuffer1);
+ screen.SHblitFrom(screen._backBuffer1);
}
void Logo::fade(const byte palette[PALETTE_SIZE], int step) {
diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp
index 6f9ef179a3..78d0cd862c 100644
--- a/engines/sherlock/scene.cpp
+++ b/engines/sherlock/scene.cpp
@@ -27,6 +27,7 @@
#include "sherlock/scalpel/scalpel_people.h"
#include "sherlock/scalpel/scalpel_scene.h"
#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/3do/scalpel_3do_screen.h"
#include "sherlock/tattoo/tattoo.h"
#include "sherlock/tattoo/tattoo_scene.h"
#include "sherlock/tattoo/tattoo_user_interface.h"
@@ -356,7 +357,7 @@ bool Scene::loadScene(const Common::String &filename) {
if (IS_ROSE_TATTOO) {
// Resize the screen if necessary
int fullWidth = SHERLOCK_SCREEN_WIDTH + bgHeader._scrollSize;
- if (screen._backBuffer1.w() != fullWidth) {
+ if (screen._backBuffer1.width() != fullWidth) {
screen._backBuffer1.create(fullWidth, SHERLOCK_SCREEN_HEIGHT);
screen._backBuffer2.create(fullWidth, SHERLOCK_SCREEN_HEIGHT);
}
@@ -649,7 +650,7 @@ bool Scene::loadScene(const Common::String &filename) {
}
// Backup the image and set the palette
- screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
screen.setPalette(screen._cMap);
delete rrmStream;
@@ -996,12 +997,12 @@ bool Scene::loadScene(const Common::String &filename) {
#if 0
// code to show the background
- screen.blitFrom(screen._backBuffer1);
+ screen.SHblitFrom(screen._backBuffer1);
_vm->_events->wait(10000);
#endif
// Backup the image
- screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
}
// Handle drawing any on-screen interface
@@ -1236,7 +1237,7 @@ void Scene::transitionToScene() {
// If the scene is capable of scrolling, set the current scroll so that whoever has control
// of the scroll code is in the middle of the screen
- if (screen._backBuffer1.w() > SHERLOCK_SCREEN_WIDTH)
+ if (screen._backBuffer1.width() > SHERLOCK_SCREEN_WIDTH)
people[people._walkControl].centerScreenOnPerson();
for (uint objIdx = 0; objIdx < _bgShapes.size(); ++objIdx) {
diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp
index 74da2a80ea..a829ab22e6 100644
--- a/engines/sherlock/screen.cpp
+++ b/engines/sherlock/screen.cpp
@@ -23,6 +23,8 @@
#include "sherlock/screen.h"
#include "sherlock/sherlock.h"
#include "sherlock/scalpel/scalpel_screen.h"
+#include "sherlock/scalpel/3do/scalpel_3do_screen.h"
+#include "sherlock/tattoo/tattoo_screen.h"
#include "common/system.h"
#include "common/util.h"
#include "graphics/palette.h"
@@ -31,17 +33,16 @@ namespace Sherlock {
Screen *Screen::init(SherlockEngine *vm) {
if (vm->getGameID() == GType_RoseTattoo)
- return new Screen(vm);
+ return new Tattoo::TattooScreen(vm);
else if (vm->getPlatform() == Common::kPlatform3DO)
return new Scalpel::Scalpel3DOScreen(vm);
else
return new Scalpel::ScalpelScreen(vm);
}
-Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm),
+Screen::Screen(SherlockEngine *vm) : BaseSurface(), _vm(vm),
_backBuffer1(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200),
- _backBuffer2(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200),
- _backBuffer(&_backBuffer1) {
+ _backBuffer2(vm->getGameID() == GType_RoseTattoo ? 640 : 320, vm->getGameID() == GType_RoseTattoo ? 480 : 200) {
_transitionSeed = 1;
_fadeStyle = false;
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
@@ -55,40 +56,21 @@ Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->get
_fadeBytesRead = _fadeBytesToRead = 0;
_oldFadePercent = 0;
_flushScreen = false;
-}
-
-Screen::~Screen() {
- Fonts::free();
-}
-
-void Screen::update() {
- // Merge the dirty rects
- mergeDirtyRects();
-
- // Loop through copying dirty areas to the physical screen
- Common::List<Common::Rect>::iterator i;
- for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) {
- const Common::Rect &r = *i;
- const byte *srcP = (const byte *)getBasePtr(r.left, r.top);
- g_system->copyRectToScreen(srcP, _surface.pitch, r.left, r.top,
- r.width(), r.height());
- }
- // Signal the physical screen to update
- g_system->updateScreen();
- _dirtyRects.clear();
+ create(_backBuffer1.w, _backBuffer1.h);
+ _backBuffer.create(_backBuffer1, _backBuffer1.getBounds());
}
-void Screen::makeAllDirty() {
- addDirtyRect(Common::Rect(0, 0, this->w(), this->h()));
+Screen::~Screen() {
+ Fonts::freeFont();
}
-void Screen::getPalette(byte palette[PALETTE_SIZE]) {
- g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT);
+void Screen::activateBackBuffer1() {
+ _backBuffer.create(_backBuffer1, _backBuffer1.getBounds());
}
-void Screen::setPalette(const byte palette[PALETTE_SIZE]) {
- g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT);
+void Screen::activateBackBuffer2() {
+ _backBuffer.create(_backBuffer2, _backBuffer2.getBounds());
}
int Screen::equalizePalette(const byte palette[PALETTE_SIZE]) {
@@ -124,7 +106,7 @@ void Screen::fadeToBlack(int speed) {
}
setPalette(tempPalette);
- fillRect(Common::Rect(0, 0, _surface.w, _surface.h), 0);
+ fillRect(Common::Rect(0, 0, this->w, this->h), 0);
}
void Screen::fadeIn(const byte palette[PALETTE_SIZE], int speed) {
@@ -136,59 +118,23 @@ void Screen::fadeIn(const byte palette[PALETTE_SIZE], int speed) {
setPalette(palette);
}
-void Screen::addDirtyRect(const Common::Rect &r) {
- _dirtyRects.push_back(r);
- assert(r.width() > 0 && r.height() > 0);
-}
-
-void Screen::mergeDirtyRects() {
- Common::List<Common::Rect>::iterator rOuter, rInner;
-
- // Process the dirty rect list to find any rects to merge
- for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
- rInner = rOuter;
- while (++rInner != _dirtyRects.end()) {
-
- if ((*rOuter).intersects(*rInner)) {
- // these two rectangles overlap or
- // are next to each other - merge them
-
- unionRectangle(*rOuter, *rOuter, *rInner);
-
- // remove the inner rect from the list
- _dirtyRects.erase(rInner);
-
- // move back to beginning of list
- rInner = rOuter;
- }
- }
- }
-}
-
-bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) {
- destRect = src1;
- destRect.extend(src2);
-
- return !destRect.isEmpty();
-}
-
void Screen::randomTransition() {
Events &events = *_vm->_events;
const int TRANSITION_MULTIPLIER = 0x15a4e35;
- _dirtyRects.clear();
+ clearDirtyRects();
assert(IS_SERRATED_SCALPEL);
for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
int offset = _transitionSeed & 0xFFFF;
- if (offset < (this->w() * this->h()))
- *((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
+ if (offset < (this->width() * this->height()))
+ *((byte *)getPixels() + offset) = *((const byte *)_backBuffer.getPixels() + offset);
if (idx != 0 && (idx % 300) == 0) {
// Ensure there's a full screen dirty rect for the next frame update
- if (_dirtyRects.empty())
- addDirtyRect(Common::Rect(0, 0, _surface.w, _surface.h));
+ if (!isDirty())
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
events.pollEvents();
events.delay(1);
@@ -196,7 +142,7 @@ void Screen::randomTransition() {
}
// Make sure everything has been transferred
- blitFrom(*_backBuffer);
+ SHblitFrom(_backBuffer);
}
void Screen::verticalTransition() {
@@ -205,13 +151,13 @@ void Screen::verticalTransition() {
byte table[640];
Common::fill(&table[0], &table[640], 0);
- for (int yp = 0; yp < this->h(); ++yp) {
- for (int xp = 0; xp < this->w(); ++xp) {
- int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] :
+ for (int yp = 0; yp < this->height(); ++yp) {
+ for (int xp = 0; xp < this->width(); ++xp) {
+ int temp = (table[xp] >= (this->height() - 3)) ? this->height() - table[xp] :
_vm->getRandomNumber(3) + 1;
if (temp) {
- blitFrom(_backBuffer1, Common::Point(xp, table[xp]),
+ SHblitFrom(_backBuffer1, Common::Point(xp, table[xp]),
Common::Rect(xp, table[xp], xp + 1, table[xp] + temp));
table[xp] += temp;
}
@@ -223,7 +169,7 @@ void Screen::verticalTransition() {
void Screen::restoreBackground(const Common::Rect &r) {
if (r.width() > 0 && r.height() > 0)
- _backBuffer->blitFrom(_backBuffer2, Common::Point(r.left, r.top), r);
+ _backBuffer.SHblitFrom(_backBuffer2, Common::Point(r.left, r.top), r);
}
void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) {
@@ -254,11 +200,10 @@ void Screen::slamRect(const Common::Rect &r) {
}
if (srcRect.isValidRect())
- blitFrom(*_backBuffer, Common::Point(destRect.left, destRect.top), srcRect);
+ SHblitFrom(_backBuffer, Common::Point(destRect.left, destRect.top), srcRect);
}
}
-
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
int16 *width, int16 *height) {
Common::Point imgPos = pt + frame->_offset;
@@ -335,7 +280,7 @@ void Screen::blockMove(const Common::Rect &r) {
}
void Screen::blockMove() {
- blockMove(Common::Rect(0, 0, w(), h()));
+ blockMove(Common::Rect(0, 0, width(), height()));
}
void Screen::print(const Common::Point &pt, uint color, const char *formatStr, ...) {
@@ -351,13 +296,13 @@ void Screen::print(const Common::Point &pt, uint color, const char *formatStr, .
pos.y--; // Font is always drawing one line higher
if (!pos.x)
// Center text horizontally
- pos.x = (this->w() - width) / 2;
+ pos.x = (this->width() - width) / 2;
Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight);
- if (textBounds.right > this->w())
- textBounds.moveTo(this->w() - width, textBounds.top);
- if (textBounds.bottom > this->h())
- textBounds.moveTo(textBounds.left, this->h() - _fontHeight);
+ if (textBounds.right > this->width())
+ textBounds.moveTo(this->width() - width, textBounds.top);
+ if (textBounds.bottom > this->height())
+ textBounds.moveTo(textBounds.left, this->height() - _fontHeight);
// Write out the string at the given position
writeString(str, Common::Point(textBounds.left, textBounds.top), color);
@@ -378,27 +323,26 @@ void Screen::gPrint(const Common::Point &pt, uint color, const char *formatStr,
}
void Screen::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
- Fonts::writeString(_backBuffer, str, pt, overrideColor);
+ Fonts::writeString(&_backBuffer, str, pt, overrideColor);
}
void Screen::vgaBar(const Common::Rect &r, int color) {
- _backBuffer->fillRect(r, color);
+ _backBuffer.fillRect(r, color);
slamRect(r);
}
void Screen::setDisplayBounds(const Common::Rect &r) {
- _sceneSurface.setPixels(_backBuffer1.getBasePtr(r.left, r.top), r.width(), r.height(), _backBuffer1.getPixelFormat());
-
- _backBuffer = &_sceneSurface;
+ _backBuffer.create(_backBuffer1, r);
+ assert(_backBuffer.width() == r.width());
+ assert(_backBuffer.height() == r.height());
}
void Screen::resetDisplayBounds() {
- _backBuffer = &_backBuffer1;
+ _backBuffer.create(_backBuffer1, _backBuffer1.getBounds());
}
Common::Rect Screen::getDisplayBounds() {
- return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) :
- Common::Rect(0, 0, this->w(), this->h());
+ return _backBuffer.getBounds();
}
void Screen::synchronize(Serializer &s) {
diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h
index 04a0c1e505..fb44c6dde2 100644
--- a/engines/sherlock/screen.h
+++ b/engines/sherlock/screen.h
@@ -25,55 +25,32 @@
#include "common/list.h"
#include "common/rect.h"
+#include "sherlock/image_file.h"
#include "sherlock/surface.h"
#include "sherlock/resources.h"
#include "sherlock/saveload.h"
namespace Sherlock {
-#define PALETTE_SIZE 768
-#define PALETTE_COUNT 256
#define VGA_COLOR_TRANS(x) ((x) * 255 / 63)
#define BG_GREYSCALE_RANGE_END 229
#define BLACK 0
class SherlockEngine;
-class Screen : public Surface {
+class Screen : public BaseSurface {
private:
- Common::List<Common::Rect> _dirtyRects;
uint32 _transitionSeed;
- Surface _sceneSurface;
// Rose Tattoo fields
int _fadeBytesRead, _fadeBytesToRead;
int _oldFadePercent;
-private:
- /**
- * Merges together overlapping dirty areas of the screen
- */
- void mergeDirtyRects();
-
- /**
- * Returns the union of two dirty area rectangles
- */
- bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
protected:
SherlockEngine *_vm;
+ Surface _backBuffer;
- /**
- * Clear the current dirty rects list
- */
- void clearDirtyRects() { _dirtyRects.clear(); }
-
- /**
- * Adds a rectangle to the list of modified areas of the screen during the
- * current frame
- */
- virtual void addDirtyRect(const Common::Rect &r);
public:
Surface _backBuffer1, _backBuffer2;
- Surface *_backBuffer;
bool _fadeStyle;
byte _cMap[PALETTE_SIZE];
byte _sMap[PALETTE_SIZE];
@@ -86,24 +63,19 @@ public:
virtual ~Screen();
/**
- * Handles updating any dirty areas of the screen Surface object to the physical screen
- */
- void update();
-
- /**
- * Makes the whole screen dirty
+ * Obtain the currently active back buffer.
*/
- void makeAllDirty();
+ Surface *getBackBuffer() { return &_backBuffer; }
/**
- * Return the currently active palette
+ * Makes first back buffer active.
*/
- void getPalette(byte palette[PALETTE_SIZE]);
+ void activateBackBuffer1();
/**
- * Set the palette
+ * Makes second back buffer active.
*/
- void setPalette(const byte palette[PALETTE_SIZE]);
+ void activateBackBuffer2();
/**
* Fades from the currently active palette to the passed palette
diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h
index b85321c385..0b4333ea3a 100644
--- a/engines/sherlock/sherlock.h
+++ b/engines/sherlock/sherlock.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SHERLOCK_HOLMES_H
-#define SHERLOCK_HOLMES_H
+#ifndef SHERLOCK_SHERLOCK_H
+#define SHERLOCK_SHERLOCK_H
#include "common/scummsys.h"
#include "common/array.h"
@@ -63,9 +63,9 @@ enum GameType {
GType_RoseTattoo = 1
};
-#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
-#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
-#define SHERLOCK_SCENE_WIDTH _vm->_screen->_backBuffer1.w()
+#define SHERLOCK_SCREEN_WIDTH _vm->_screen->width()
+#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->height()
+#define SHERLOCK_SCENE_WIDTH _vm->_screen->_backBuffer1.width()
#define SHERLOCK_SCENE_HEIGHT (IS_SERRATED_SCALPEL ? 138 : 480)
#define SCENES_COUNT (IS_SERRATED_SCALPEL ? 63 : 101)
#define MAX_BGSHAPES (IS_SERRATED_SCALPEL ? 64 : 150)
diff --git a/engines/sherlock/sound.h b/engines/sherlock/sound.h
index 0a0ff83d1f..a82aaf6730 100644
--- a/engines/sherlock/sound.h
+++ b/engines/sherlock/sound.h
@@ -25,11 +25,8 @@
#include "common/scummsys.h"
#include "common/str.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "access/files.h"
-#include "audio/midiplayer.h"
-#include "audio/midiparser.h"
namespace Sherlock {
diff --git a/engines/sherlock/surface.cpp b/engines/sherlock/surface.cpp
index b7fc76325c..93bc001149 100644
--- a/engines/sherlock/surface.cpp
+++ b/engines/sherlock/surface.cpp
@@ -21,252 +21,24 @@
*/
#include "sherlock/surface.h"
-#include "sherlock/sherlock.h"
-#include "sherlock/resources.h"
-#include "common/system.h"
-#include "graphics/palette.h"
+#include "sherlock/fonts.h"
namespace Sherlock {
-Surface::Surface(uint16 width, uint16 height) : Fonts(), _freePixels(true) {
- create(width, height);
-}
-
-Surface::Surface() : Fonts(), _freePixels(false) {
-}
-
-Surface::~Surface() {
- if (_freePixels)
- _surface.free();
-}
-
-void Surface::create(uint16 width, uint16 height) {
- if (_freePixels)
- _surface.free();
-
- if (_vm->getPlatform() == Common::kPlatform3DO) {
- _surface.create(width, height, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
- } else {
- _surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
- }
- _freePixels = true;
-}
-
-Graphics::PixelFormat Surface::getPixelFormat() {
- return _surface.format;
-}
-
-void Surface::blitFrom(const Surface &src) {
- blitFrom(src, Common::Point(0, 0));
-}
-
-void Surface::blitFrom(const ImageFrame &src) {
- blitFrom(src._frame, Common::Point(0, 0));
-}
-
-void Surface::blitFrom(const Graphics::Surface &src) {
- blitFrom(src, Common::Point(0, 0));
-}
-
-void Surface::blitFrom(const Surface &src, const Common::Point &pt) {
- blitFrom(src, pt, Common::Rect(0, 0, src._surface.w, src._surface.h));
-}
-
-void Surface::blitFrom(const ImageFrame &src, const Common::Point &pt) {
- blitFrom(src._frame, pt, Common::Rect(0, 0, src._frame.w, src._frame.h));
-}
-
-void Surface::blitFrom(const Graphics::Surface &src, const Common::Point &pt) {
- blitFrom(src, pt, Common::Rect(0, 0, src.w, src.h));
-}
-
-void Surface::blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) {
- Common::Rect srcRect = srcBounds;
- Common::Rect destRect(pt.x, pt.y, pt.x + srcRect.width(), pt.y + srcRect.height());
-
- if (srcRect.isValidRect() && clip(srcRect, destRect)) {
- // Surface is at least partially or completely on-screen
- addDirtyRect(destRect);
- _surface.copyRectToSurface(src, destRect.left, destRect.top, srcRect);
- }
-}
-
-void Surface::blitFrom(const ImageFrame &src, const Common::Point &pt, const Common::Rect &srcBounds) {
- blitFrom(src._frame, pt, srcBounds);
-}
-
-void Surface::blitFrom(const Surface &src, const Common::Point &pt, const Common::Rect &srcBounds) {
- blitFrom(src._surface, pt, srcBounds);
-}
-
-void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt,
- bool flipped, int overrideColor, int scaleVal) {
- Common::Point drawPt(pt.x + src.sDrawXOffset(scaleVal), pt.y + src.sDrawYOffset(scaleVal));
- transBlitFrom(src._frame, drawPt, flipped, overrideColor, scaleVal);
-}
-
-void Surface::transBlitFrom(const Surface &src, const Common::Point &pt,
- bool flipped, int overrideColor, int scaleVal) {
- const Graphics::Surface &s = src._surface;
- transBlitFrom(s, pt, flipped, overrideColor, scaleVal);
-}
-
-void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
- bool flipped, int overrideColor, int scaleVal) {
- if (scaleVal == SCALE_THRESHOLD) {
- transBlitFromUnscaled(src, pt, flipped, overrideColor);
- return;
- }
-
- int destWidth = src.w * SCALE_THRESHOLD / scaleVal;
- int destHeight = src.h * SCALE_THRESHOLD / scaleVal;
-
- // Loop through drawing output lines
- for (int destY = pt.y, scaleYCtr = 0; destY < (pt.y + destHeight); ++destY, scaleYCtr += scaleVal) {
- if (destY < 0 || destY >= this->h())
- continue;
- const byte *srcLine = (const byte *)src.getBasePtr(0, scaleYCtr / SCALE_THRESHOLD);
- byte *destLine = (byte *)getBasePtr(pt.x, destY);
-
- // Loop through drawing individual rows
- for (int xCtr = 0, scaleXCtr = 0; xCtr < destWidth; ++xCtr, scaleXCtr += scaleVal) {
- int destX = pt.x + xCtr;
- if (destX < 0 || destX >= this->w())
- continue;
-
- byte srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD];
- if (srcVal != TRANSPARENCY)
- destLine[xCtr] = srcVal;
- }
- }
-
- // Mark the affected area
- addDirtyRect(Common::Rect(pt.x, pt.y, pt.x + destWidth, pt.y + destHeight));
-}
-
-void Surface::transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt,
- bool flipped, int overrideColor) {
- Common::Rect drawRect(0, 0, src.w, src.h);
- Common::Rect destRect(pt.x, pt.y, pt.x + src.w, pt.y + src.h);
-
- // Clip the display area to on-screen
- if (!clip(drawRect, destRect))
- // It's completely off-screen
- return;
-
- if (flipped)
- drawRect = Common::Rect(src.w - drawRect.right, drawRect.top,
- src.w - drawRect.left, drawRect.bottom);
-
- Common::Point destPt(destRect.left, destRect.top);
- addDirtyRect(Common::Rect(destPt.x, destPt.y, destPt.x + drawRect.width(),
- destPt.y + drawRect.height()));
-
- switch (src.format.bytesPerPixel) {
- case 1:
- // 8-bit palettized: Draw loop
- assert(_surface.format.bytesPerPixel == 1); // Security check
- for (int yp = 0; yp < drawRect.height(); ++yp) {
- const byte *srcP = (const byte *)src.getBasePtr(
- flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp);
- byte *destP = (byte *)getBasePtr(destPt.x, destPt.y + yp);
-
- for (int xp = 0; xp < drawRect.width(); ++xp, ++destP) {
- if (*srcP != TRANSPARENCY)
- *destP = overrideColor ? overrideColor : *srcP;
-
- srcP = flipped ? srcP - 1 : srcP + 1;
- }
- }
- break;
- case 2:
- // 3DO 15-bit RGB565: Draw loop
- assert(_surface.format.bytesPerPixel == 2); // Security check
- for (int yp = 0; yp < drawRect.height(); ++yp) {
- const uint16 *srcP = (const uint16 *)src.getBasePtr(
- flipped ? drawRect.right - 1 : drawRect.left, drawRect.top + yp);
- uint16 *destP = (uint16 *)getBasePtr(destPt.x, destPt.y + yp);
-
- for (int xp = 0; xp < drawRect.width(); ++xp, ++destP) {
- if (*srcP) // RGB 0, 0, 0 -> transparent on 3DO
- *destP = *srcP; // overrideColor ? overrideColor : *srcP;
-
- srcP = flipped ? srcP - 1 : srcP + 1;
- }
- }
- break;
- default:
- error("Surface: unsupported bytesperpixel");
- break;
- }
-}
-
-void Surface::fillRect(int x1, int y1, int x2, int y2, uint color) {
- fillRect(Common::Rect(x1, y1, x2, y2), color);
-}
-
-void Surface::fillRect(const Common::Rect &r, uint color) {
- _surface.fillRect(r, color);
- addDirtyRect(r);
-}
-
-void Surface::fill(uint color) {
- fillRect(Common::Rect(_surface.w, _surface.h), color);
+BaseSurface::BaseSurface() : Graphics::Screen(0, 0), Fonts() {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
}
-bool Surface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) {
- if (destBounds.left >= w() || destBounds.top >= h() ||
- destBounds.right <= 0 || destBounds.bottom <= 0)
- return false;
-
- // Clip the bounds if necessary to fit on-screen
- if (destBounds.right > w()) {
- srcBounds.right -= destBounds.right - w();
- destBounds.right = w();
- }
-
- if (destBounds.bottom > h()) {
- srcBounds.bottom -= destBounds.bottom - h();
- destBounds.bottom = h();
- }
-
- if (destBounds.top < 0) {
- srcBounds.top += -destBounds.top;
- destBounds.top = 0;
- }
-
- if (destBounds.left < 0) {
- srcBounds.left += -destBounds.left;
- destBounds.left = 0;
- }
-
- return true;
-}
-
-void Surface::clear() {
- fillRect(Common::Rect(0, 0, w(), h()), 0);
-}
-
-void Surface::free() {
- if (_freePixels) {
- _surface.free();
- _freePixels = false;
- }
-}
-
-void Surface::setPixels(byte *pixels, int width, int height, Graphics::PixelFormat pixelFormat) {
- _surface.format = pixelFormat;
- _surface.w = width;
- _surface.h = height;
- _surface.pitch = width * pixelFormat.bytesPerPixel;
- _surface.setPixels(pixels);
+BaseSurface::BaseSurface(int width, int height) : Graphics::Screen(width, height),
+ Fonts() {
+ create(width, height);
}
-void Surface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
+void BaseSurface::writeString(const Common::String &str, const Common::Point &pt, uint overrideColor) {
Fonts::writeString(this, str, pt, overrideColor);
}
-void Surface::writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2) {
+void BaseSurface::writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2) {
writeString(str, Common::Point(pt.x, pt.y), overrideColor1);
writeString(str, Common::Point(pt.x + 1, pt.y), overrideColor1);
writeString(str, Common::Point(pt.x + 2, pt.y), overrideColor1);
@@ -278,4 +50,21 @@ void Surface::writeFancyString(const Common::String &str, const Common::Point &p
writeString(str, Common::Point(pt.x + 1, pt.y + 1), overrideColor2);
}
+void BaseSurface::SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt,
+ bool flipped, int overrideColor, int scaleVal) {
+ Common::Point drawPt(pt.x + src.sDrawXOffset(scaleVal), pt.y + src.sDrawYOffset(scaleVal));
+ SHtransBlitFrom(src._frame, drawPt, flipped, overrideColor, scaleVal);
+}
+
+void BaseSurface::SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
+ bool flipped, int overrideColor, int scaleVal) {
+ Common::Rect srcRect(0, 0, src.w, src.h);
+ Common::Rect destRect(pt.x, pt.y, pt.x + src.w * SCALE_THRESHOLD / scaleVal,
+ pt.y + src.h * SCALE_THRESHOLD / scaleVal);
+
+ Graphics::Screen::transBlitFrom(src, srcRect, destRect, TRANSPARENCY,
+ flipped, overrideColor);
+}
+
+
} // End of namespace Sherlock
diff --git a/engines/sherlock/surface.h b/engines/sherlock/surface.h
index 378c9be9cd..401d9b648d 100644
--- a/engines/sherlock/surface.h
+++ b/engines/sherlock/surface.h
@@ -20,165 +20,108 @@
*
*/
-#ifndef SHERLOCK_GRAPHICS_H
-#define SHERLOCK_GRAPHICS_H
+#ifndef SHERLOCK_SURFACE_H
+#define SHERLOCK_SURFACE_H
#include "common/rect.h"
#include "common/platform.h"
-#include "graphics/surface.h"
+#include "graphics/screen.h"
#include "sherlock/fonts.h"
+#include "sherlock/image_file.h"
namespace Sherlock {
#define SCALE_THRESHOLD 0x100
#define TRANSPARENCY 255
-struct ImageFrame;
-
-class Surface: public Fonts {
-private:
- bool _freePixels;
-
- /**
- * Copy a surface into this one
- */
- void blitFrom(const Graphics::Surface &src);
-protected:
- Graphics::Surface _surface;
-
- /**
- * Clips the given source bounds so the passed destBounds will be entirely on-screen
- */
- bool clip(Common::Rect &srcBounds, Common::Rect &destBounds);
-
- /**
- * Base method stub for signalling dirty rect areas
- */
- virtual void addDirtyRect(const Common::Rect &r) {}
-
- /**
- * Draws a sub-section of a surface at a given position within this surface
- */
- virtual void blitFrom(const Graphics::Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
-
- /**
- * Draws a surface at a given position within this surface with transparency
- */
- virtual void transBlitFromUnscaled(const Graphics::Surface &src, const Common::Point &pt, bool flipped,
- int overrideColor);
+/**
+ * Implements a base surface that combines both a managed surface and the font
+ * drawing code. It also introduces a series of drawing method stubs that the 3DO
+ * Serrated Scalpel screen overrides to implement sprite doubling
+ */
+class BaseSurface: public Graphics::Screen, public Fonts {
public:
- Surface(uint16 width, uint16 height);
- Surface();
- virtual ~Surface();
-
/**
- * Sets up an internal surface with the specified dimensions that will be automatically freed
- * when the surface object is destroyed
+ * Constructor
*/
- void create(uint16 width, uint16 height);
-
- Graphics::PixelFormat getPixelFormat();
+ BaseSurface();
/**
- * Copy a surface into this one
+ * Constructor
*/
- void blitFrom(const Surface &src);
+ BaseSurface(int width, int height);
/**
- * Copy an image frame into this surface
+ * Draws a surface on this surface
*/
- void blitFrom(const ImageFrame &src);
+ virtual void SHblitFrom(const Graphics::Surface &src) {
+ Graphics::ManagedSurface::blitFrom(src);
+ }
/**
* Draws a surface at a given position within this surface
*/
- void blitFrom(const Surface &src, const Common::Point &pt);
-
- /**
- * Copy an image frame onto this surface at a given position
- */
- void blitFrom(const ImageFrame &src, const Common::Point &pt);
+ virtual void SHblitFrom(const Graphics::Surface &src, const Common::Point &destPos) {
+ Graphics::ManagedSurface::blitFrom(src, destPos);
+ }
/**
* Draws a sub-section of a surface at a given position within this surface
*/
- void blitFrom(const Surface &src, const Common::Point &pt, const Common::Rect &srcBounds);
-
- /**
- * Copy a sub-area of a source image frame into this surface at a given position
- */
- void blitFrom(const ImageFrame &src, const Common::Point &pt, const Common::Rect &srcBounds);
-
- /**
- * Draws a surface at a given position within this surface
- */
- void blitFrom(const Graphics::Surface &src, const Common::Point &pt);
+ virtual void SHblitFrom(const Graphics::Surface &src, const Common::Point &destPos, const Common::Rect &srcBounds) {
+ Graphics::ManagedSurface::blitFrom(src, srcBounds, destPos);
+ }
/**
* Draws an image frame at a given position within this surface with transparency
*/
- void transBlitFrom(const ImageFrame &src, const Common::Point &pt,
- bool flipped = false, int overrideColor = 0, int scaleVal = 256);
-
- /**
- * Draws a surface at a given position within this surface with transparency
- */
- void transBlitFrom(const Surface &src, const Common::Point &pt,
- bool flipped = false, int overrideColor = 0, int scaleVal = 256);
+ void SHtransBlitFrom(const ImageFrame &src, const Common::Point &pt,
+ bool flipped = false, int overrideColor = 0, int scaleVal = SCALE_THRESHOLD);
/**
- * Draws a surface at a given position within this surface with transparency
+ * Draws an image frame at a given position within this surface with transparency
*/
- void transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
- bool flipped = false, int overrideColor = 0, int scaleVal = 256);
+ void SHtransBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
+ bool flipped = false, int overrideColor = 0, int scaleVal = SCALE_THRESHOLD);
/**
* Fill a given area of the surface with a given color
*/
- void fillRect(int x1, int y1, int x2, int y2, uint color);
-
- /**
- * Fill a given area of the surface with a given color
- */
- virtual void fillRect(const Common::Rect &r, uint color);
-
- void fill(uint color);
-
- /**
- * Clear the surface
- */
- void clear();
+ virtual void SHfillRect(const Common::Rect &r, uint color) {
+ Graphics::ManagedSurface::fillRect(r, color);
+ }
/**
- * Free the underlying surface
+ * Return the width of the surface
*/
- void free();
+ virtual uint16 width() const { return this->w; }
/**
- * Returns true if the surface is empty
+ * Return the height of the surface
*/
- bool empty() const { return _surface.getPixels() == nullptr; }
+ virtual uint16 height() const { return this->h; }
/**
- * Set the pixels for the surface to an existing data block
+ * Draws the given string into the back buffer using the images stored in _font
*/
- void setPixels(byte *pixels, int width, int height, Graphics::PixelFormat format);
+ void writeString(const Common::String &str, const Common::Point &pt, uint overrideColor);
/**
- * Draws the given string into the back buffer using the images stored in _font
+ * Draws a fancy version of the given string at the given position
*/
- virtual void writeString(const Common::String &str, const Common::Point &pt, uint overrideColor);
void writeFancyString(const Common::String &str, const Common::Point &pt, uint overrideColor1, uint overrideColor2);
+};
- inline virtual uint16 w() const { return _surface.w; }
- inline virtual uint16 h() const { return _surface.h; }
- inline const byte *getPixels() const { return (const byte *)_surface.getPixels(); }
- inline byte *getPixels() { return (byte *)_surface.getPixels(); }
- inline byte *getBasePtr(int x, int y) { return (byte *)_surface.getBasePtr(x, y); }
- inline const byte *getBasePtr(int x, int y) const { return (const byte *)_surface.getBasePtr(x, y); }
- inline Graphics::Surface &getRawSurface() { return _surface; }
- inline void hLine(int x, int y, int x2, uint color) { _surface.hLine(x, y, x2, color); }
- inline void vLine(int x, int y, int y2, uint color) { _surface.vLine(x, y, y2, color); }
+class Surface : public BaseSurface {
+protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
+public:
+ Surface() : BaseSurface() {}
+ Surface(int width, int height) : BaseSurface(width, height) {}
};
} // End of namespace Sherlock
diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp
index b543472513..3c6bf44837 100644
--- a/engines/sherlock/talk.cpp
+++ b/engines/sherlock/talk.cpp
@@ -28,9 +28,11 @@
#include "sherlock/scalpel/scalpel_talk.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
#include "sherlock/tattoo/tattoo.h"
+#include "sherlock/tattoo/tattoo_fixed_text.h"
#include "sherlock/tattoo/tattoo_people.h"
#include "sherlock/tattoo/tattoo_scene.h"
#include "sherlock/tattoo/tattoo_talk.h"
+#include "sherlock/tattoo/tattoo_user_interface.h"
namespace Sherlock {
@@ -306,8 +308,14 @@ void Talk::talkTo(const Common::String filename) {
if (_scriptMoreFlag && _scriptSelect != 100)
select = _scriptSelect;
- if (select == -1)
+ if (select == -1) {
+ if (IS_ROSE_TATTOO) {
+ static_cast<Tattoo::TattooUserInterface *>(&ui)->putMessage(
+ "%s", _vm->_fixedText->getText(Tattoo::kFixedText_NoEffect));
+ return;
+ }
error("Couldn't find statement to display");
+ }
// Add the statement into the journal and talk history
if (_talkTo != -1 && !_talkHistory[_converseNum][select])
diff --git a/engines/sherlock/tattoo/tattoo_darts.cpp b/engines/sherlock/tattoo/tattoo_darts.cpp
index fe707a8c13..cbc3ea1fe8 100644
--- a/engines/sherlock/tattoo/tattoo_darts.cpp
+++ b/engines/sherlock/tattoo/tattoo_darts.cpp
@@ -163,7 +163,7 @@ void Darts::playDarts(GameType gameType) {
// Show scores
showStatus(playerNum);
- screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, FIXED(DartsCurrentDart), idx + 1);
@@ -178,7 +178,7 @@ void Darts::playDarts(GameType gameType) {
scoredPoints = Common::String::format(FIXED(DartsScoredPoints), lastDart);
}
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, scoredPoints.c_str());
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", scoredPoints.c_str());
} else {
Common::String hitText;
@@ -213,7 +213,7 @@ void Darts::playDarts(GameType gameType) {
break;
}
}
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, hitText.c_str());
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top + _spacing), 0, "%s", hitText.c_str());
}
if (score != 0 && playerNum == 0 && !gameOver)
@@ -267,10 +267,11 @@ void Darts::playDarts(GameType gameType) {
} else {
events.wait(40);
}
+
// Clears the status part of the board
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
- screen.blitFrom(screen._backBuffer1);
+ screen.SHblitFrom(screen._backBuffer1);
}
playerNum ^= 1;
@@ -278,9 +279,9 @@ void Darts::playDarts(GameType gameType) {
++_roundNum;
if (!done) {
- screen._backBuffer2.blitFrom((*_dartBoard)[0], Common::Point(0, 0));
- screen._backBuffer1.blitFrom(screen._backBuffer2);
- screen.blitFrom(screen._backBuffer2);
+ screen._backBuffer2.SHblitFrom((*_dartBoard)[0], Common::Point(0, 0));
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2);
+ screen.SHblitFrom(screen._backBuffer2);
}
}
@@ -367,9 +368,9 @@ void Darts::loadDarts() {
delete stream;
// Load the initial background
- screen._backBuffer1.blitFrom((*_dartBoard)[0], Common::Point(0, 0));
- screen._backBuffer2.blitFrom(screen._backBuffer1);
- screen.blitFrom(screen._backBuffer1);
+ screen._backBuffer1.SHblitFrom((*_dartBoard)[0], Common::Point(0, 0));
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
+ screen.SHblitFrom(screen._backBuffer1);
}
void Darts::closeDarts() {
@@ -399,14 +400,14 @@ void Darts::showNames(int playerNum) {
screen.fillRect(Common::Rect(STATUS2_INFO_X, STATUS_INFO_Y + _spacing + 1,
STATUS2_INFO_X + 50, STATUS_INFO_Y + _spacing + 3), color);
- screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
}
void Darts::showStatus(int playerNum) {
Screen &screen = *_vm->_screen;
const char *const CRICKET_SCORE_NAME[7] = { "20", "19", "18", "17", "16", "15", FIXED(DartsBull) };
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH,
STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10));
screen.print(Common::Point(STATUS_INFO_X + 30, STATUS_INFO_Y + _spacing + 4), 0, "%d", _score1);
@@ -417,12 +418,12 @@ void Darts::showStatus(int playerNum) {
// "Round: x"
Common::String dartsRoundStatus = Common::String::format(FIXED(DartsCurrentRound), _roundNum);
- screen.print(Common::Point(STATUS_INFO_X, temp), 0, dartsRoundStatus.c_str());
+ screen.print(Common::Point(STATUS_INFO_X, temp), 0, "%s", dartsRoundStatus.c_str());
if (_gameType == GAME_301) {
// "Turn Total: x"
Common::String dartsTotalPoints = Common::String::format(FIXED(DartsCurrentTotalPoints), _roundScore);
- screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, dartsTotalPoints.c_str());
+ screen.print(Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 75), 0, "%s", dartsTotalPoints.c_str());
} else {
// Show cricket scores
for (int x = 0; x < 7; ++x) {
@@ -447,7 +448,7 @@ void Darts::showStatus(int playerNum) {
}
}
- screen.blitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
+ screen.SHblitFrom(screen._backBuffer1, Common::Point(STATUS_INFO_X, STATUS_INFO_Y + 10),
Common::Rect(STATUS_INFO_X, STATUS_INFO_Y + 10, STATUS_INFO_X + STATUS_INFO_WIDTH,
STATUS_INFO_Y + STATUS_INFO_HEIGHT - 10));
}
@@ -457,7 +458,7 @@ void Darts::erasePowerBars() {
// Erase the old power bars and replace them with empty ones
screen._backBuffer1.fillRect(Common::Rect(DART_BAR_VX, DART_HEIGHT_Y, DART_BAR_VX + 9, DART_HEIGHT_Y + DART_BAR_SIZE), 0);
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[0], Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1));
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[0], Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1));
screen.slamArea(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, 10, DART_BAR_SIZE + 2);
}
@@ -497,7 +498,7 @@ int Darts::doPowerBar(const Common::Point &pt, byte color, int goToPower, int or
}
screen._backBuffer1.hLine(pt.x, pt.y + DART_BAR_SIZE- 1 - idx, pt.x + 8, color);
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[0], Common::Point(pt.x - 1, pt.y - 1));
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[0], Common::Point(pt.x - 1, pt.y - 1));
screen.slamArea(pt.x, pt.y + DART_BAR_SIZE - 1 - idx, 8, 2);
if (!(idx % 8))
@@ -544,7 +545,7 @@ int Darts::drawHand(int goToPower, int computer) {
break;
}
- screen._backBuffer1.transBlitFrom((*hands)[0], pt);
+ screen._backBuffer1.SHtransBlitFrom((*hands)[0], pt);
screen.slamArea(pt.x - 1, pt.y, _handSize.x + 1, _handSize.y);
screen.restoreBackground(Common::Rect(pt.x, pt.y, pt.x + _handSize.x, pt.y + _handSize.y));
@@ -631,7 +632,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
_handSize.y = hands[idx]._offset.y + hands[idx]._height;
int handCy = SHERLOCK_SCREEN_HEIGHT - _handSize.y;
- screen._backBuffer1.transBlitFrom(hands[idx], Common::Point(_handX, handCy));
+ screen._backBuffer1.SHtransBlitFrom(hands[idx], Common::Point(_handX, handCy));
screen.slamArea(_handX, handCy, _handSize.x + 1, _handSize.y);
screen.slamArea(handOCx, handOCy, handOldxSize, handOldySize);
screen.restoreBackground(Common::Rect(_handX, handCy, _handX + _handSize.x, handCy + _handSize.y));
@@ -653,7 +654,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height;
// Draw dart
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], drawPos);
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], drawPos);
if (drawPos.x < 0) {
xSize += drawPos.x;
@@ -675,7 +676,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
// Flush the erased dart area
screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize));
oldDrawPos.x = drawPos.x;
@@ -696,7 +697,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
if (oldDrawPos.x != -1)
screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(drawPos.x, drawPos.y),
Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize));
cx = dartPos.x;
@@ -722,7 +723,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
ocx = drawPos.x = cx - (*_dartGraphics)[dartNum]._width / 2;
ocy = drawPos.y = cy - (*_dartGraphics)[dartNum]._height;
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawPos.x, drawPos.y));
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(drawPos.x, drawPos.y));
if (drawPos.x < 0) {
xSize += drawPos.x;
@@ -744,7 +745,7 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
screen.slamArea(oldDrawPos.x, oldDrawPos.y, oldxSize, oldySize);
if (idx != 23)
- screen._backBuffer1.blitFrom(screen._backBuffer2, drawPos,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, drawPos,
Common::Rect(drawPos.x, drawPos.y, drawPos.x + xSize, drawPos.y + ySize)); // erase dart
events.wait(1);
@@ -761,8 +762,8 @@ void Darts::drawDartThrow(const Common::Point &dartPos, int computer) {
ySize = (*_dartGraphics)[dartNum]._height;
// Draw final dart on the board
- screen._backBuffer1.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
- screen._backBuffer2.transBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
+ screen._backBuffer1.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
+ screen._backBuffer2.SHtransBlitFrom((*_dartGraphics)[dartNum], Common::Point(ocx, ocy));
screen.slamArea(ocx, ocy, xSize, ySize);
}
@@ -935,7 +936,7 @@ int Darts::throwDart(int dartNum, int computer) {
// "Dart # x"
Common::String currentDart = Common::String::format(FIXED(DartsCurrentDart), dartNum);
- screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, currentDart.c_str());
+ screen.print(Common::Point(_dartInfo.left, _dartInfo.top), 0, "%s", currentDart.c_str());
drawDartsLeft(dartNum, computer);
@@ -955,9 +956,9 @@ int Darts::throwDart(int dartNum, int computer) {
}
drawDartsLeft(dartNum + 1, computer);
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_dartInfo.left, _dartInfo.top - 1),
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
- screen.blitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
+ screen.SHblitFrom(screen._backBuffer1, Common::Point(_dartInfo.left, _dartInfo.top - 1),
Common::Rect(_dartInfo.left, _dartInfo.top - 1, _dartInfo.right, _dartInfo.bottom - 1));
if (computer) {
@@ -979,7 +980,7 @@ int Darts::throwDart(int dartNum, int computer) {
height = 101 - height;
// Copy power bars to the secondary back buffer
- screen._backBuffer2.blitFrom(screen._backBuffer1, Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1),
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1, Common::Point(DART_BAR_VX - 1, DART_HEIGHT_Y - 1),
Common::Rect(DART_BAR_VX - 1, DART_HEIGHT_Y - 1, DART_BAR_VX - 1 + 10,
DART_HEIGHT_Y - 1 + DART_BAR_SIZE + 2));
@@ -1023,14 +1024,14 @@ void Darts::drawDartsLeft(int dartNum, int computer) {
const int DART_X2[3] = { 393, 441, 502 };
const int DART_Y2[3] = { 373, 373, 373 };
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(DART_X1[0], DART_Y1[0]),
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(DART_X1[0], DART_Y1[0]),
Common::Rect(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
for (int idx = 2; idx >= dartNum - 1; --idx) {
if (computer)
- screen._backBuffer1.transBlitFrom((*_dartsLeft)[idx + 3], Common::Point(DART_X2[idx], DART_Y2[idx]));
+ screen._backBuffer1.SHtransBlitFrom((*_dartsLeft)[idx + 3], Common::Point(DART_X2[idx], DART_Y2[idx]));
else
- screen._backBuffer1.transBlitFrom((*_dartsLeft)[idx], Common::Point(DART_X1[idx], DART_Y1[idx]));
+ screen._backBuffer1.SHtransBlitFrom((*_dartsLeft)[idx], Common::Point(DART_X1[idx], DART_Y1[idx]));
}
screen.slamArea(DART_X1[0], DART_Y1[0], SHERLOCK_SCREEN_WIDTH - DART_X1[0], SHERLOCK_SCREEN_HEIGHT - DART_Y1[0]);
diff --git a/engines/sherlock/tattoo/tattoo_fixed_text.h b/engines/sherlock/tattoo/tattoo_fixed_text.h
index 7dbe13bbb3..eb636cdada 100644
--- a/engines/sherlock/tattoo/tattoo_fixed_text.h
+++ b/engines/sherlock/tattoo/tattoo_fixed_text.h
@@ -233,7 +233,7 @@ public:
virtual const Common::String getActionMessage(FixedTextActionId actionId, int messageIndex);
};
-} // End of namespace Scalpel
+} // End of namespace Tattoo
} // End of namespace Sherlock
diff --git a/engines/sherlock/tattoo/tattoo_journal.cpp b/engines/sherlock/tattoo/tattoo_journal.cpp
index dac0760ad2..4d4f37f8d5 100644
--- a/engines/sherlock/tattoo/tattoo_journal.cpp
+++ b/engines/sherlock/tattoo/tattoo_journal.cpp
@@ -50,7 +50,7 @@ void TattooJournal::show() {
Screen &screen = *_vm->_screen;
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
byte palette[PALETTE_SIZE];
-
+
Common::Point oldScroll = screen._currentScroll;
screen._currentScroll = Common::Point(0, 0);
@@ -65,8 +65,8 @@ void TattooJournal::show() {
delete stream;
// Set screen to black, and set background
- screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0));
- screen.empty();
+ screen._backBuffer1.SHblitFrom((*_journalImages)[0], Common::Point(0, 0));
+ screen.clear();
screen.setPalette(palette);
if (_journal.empty()) {
@@ -87,12 +87,12 @@ void TattooJournal::show() {
handleKeyboardEvents();
highlightJournalControls(true);
-
+
handleButtons();
if (_wait)
events.wait(2);
-
+
} while (!_vm->shouldQuit() && !_exitJournal);
// Clear events
@@ -275,7 +275,7 @@ void TattooJournal::handleButtons() {
if (frameCounter >= _scrollingTimer) {
// Set next scrolling time
_scrollingTimer = frameCounter + 6;
-
+
// Handle different scrolling actions
switch (_selector) {
case JH_SCROLL_LEFT:
@@ -355,13 +355,13 @@ void TattooJournal::handleButtons() {
_savedIndex = _index;
_savedSub = _sub;
_savedPage = _page;
-
+
bool drawResult = drawJournal(dir + 2, 1000 * LINES_PER_PAGE);
if (!drawResult) {
_index = _savedIndex;
_sub = _savedSub;
_page = _savedPage;
-
+
drawFrame();
drawJournal(0, 0);
notFound = true;
@@ -461,7 +461,7 @@ void TattooJournal::loadLocations() {
void TattooJournal::drawFrame() {
Screen &screen = *_vm->_screen;
- screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0));
+ screen._backBuffer1.SHblitFrom((*_journalImages)[0], Common::Point(0, 0));
drawControls(0);
}
@@ -486,10 +486,10 @@ void TattooJournal::drawControls(int mode) {
screen._backBuffer1.fillRect(inner, MENU_BACKGROUND);
// Draw the four corners of the info box
- screen._backBuffer1.transBlitFrom(images[0], Common::Point(r.left, r.top));
- screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.top));
- screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.left, r.bottom - images[1]._height));
- screen._backBuffer1.transBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.bottom - images[1]._height));
+ screen._backBuffer1.SHtransBlitFrom(images[0], Common::Point(r.left, r.top));
+ screen._backBuffer1.SHtransBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.top));
+ screen._backBuffer1.SHtransBlitFrom(images[1], Common::Point(r.left, r.bottom - images[1]._height));
+ screen._backBuffer1.SHtransBlitFrom(images[1], Common::Point(r.right - images[1]._width, r.bottom - images[1]._height));
// Draw the top of the info box
screen._backBuffer1.hLine(r.left + images[0]._width, r.top, r.right - images[0]._height, INFO_TOP);
@@ -513,8 +513,8 @@ void TattooJournal::drawControls(int mode) {
// Draw the sides of the separator bar above the scroll bar
int yp = r.top + screen.fontHeight() + 7;
- screen._backBuffer1.transBlitFrom(images[4], Common::Point(r.left, yp - 1));
- screen._backBuffer1.transBlitFrom(images[5], Common::Point(r.right - images[5]._width, yp - 1));
+ screen._backBuffer1.SHtransBlitFrom(images[4], Common::Point(r.left, yp - 1));
+ screen._backBuffer1.SHtransBlitFrom(images[5], Common::Point(r.right - images[5]._width, yp - 1));
// Draw the bar above the scroll bar
screen._backBuffer1.hLine(r.left + images[4]._width, yp, r.right - images[5]._width, INFO_TOP);
@@ -523,15 +523,15 @@ void TattooJournal::drawControls(int mode) {
if (mode != 2) {
// Draw the Bars separating the Journal Commands
- int xp = r.right / 3;
+ int xp = r.left + r.width() / 3;
for (int idx = 0; idx < 2; ++idx) {
- screen._backBuffer1.transBlitFrom(images[6], Common::Point(xp - 2, r.top + 1));
- screen._backBuffer1.transBlitFrom(images[7], Common::Point(xp - 2, yp - 1));
+ screen._backBuffer1.SHtransBlitFrom(images[6], Common::Point(xp - 2, r.top + 1));
+ screen._backBuffer1.SHtransBlitFrom(images[7], Common::Point(xp - 2, yp - 1));
- screen._backBuffer1.hLine(xp - 1, r.top + 4, yp - 2, INFO_TOP);
- screen._backBuffer1.hLine(xp, r.top + 4, yp - 2, INFO_MIDDLE);
- screen._backBuffer1.hLine(xp + 1, r.top + 4, yp - 2, INFO_BOTTOM);
- xp = r.right / 3 * 2;
+ screen._backBuffer1.vLine(xp - 1, r.top + 4, yp - 2, INFO_TOP);
+ screen._backBuffer1.vLine(xp, r.top + 4, yp - 2, INFO_MIDDLE);
+ screen._backBuffer1.vLine(xp + 1, r.top + 4, yp - 2, INFO_BOTTOM);
+ xp += r.width() / 3;
}
}
@@ -539,7 +539,7 @@ void TattooJournal::drawControls(int mode) {
_oldSelector = 100;
switch (mode) {
- case 0:
+ case 0:
highlightJournalControls(false);
break;
case 1:
@@ -548,7 +548,7 @@ void TattooJournal::drawControls(int mode) {
default:
break;
}
-
+
_oldSelector = savedSelector;
}
@@ -558,7 +558,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
Common::Point mousePos = events.mousePos();
Common::Rect r(JOURNAL_BAR_WIDTH, BUTTON_SIZE + screen.fontHeight() + 13);
r.moveTo((SHERLOCK_SCREEN_WIDTH - r.width()) / 2, SHERLOCK_SCREEN_HEIGHT - r.height());
-
+
if ((events._pressed || events._released) && _selector == JH_THUMBNAIL) {
if (events._released)
_selector = JH_NONE;
@@ -576,7 +576,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
_selector = JH_NONE;
if (bounds.contains(mousePos))
_selector = (mousePos.x - r.left) / (r.width() / 3);
-
+
else if (events._pressed && mousePos.y >= (r.top + screen.fontHeight() + 10)
&& mousePos.y < (r.top + screen.fontHeight() + 10 + BUTTON_SIZE)) {
if (mousePos.x >= r.left && mousePos.x < (r.left + BUTTON_SIZE))
@@ -628,7 +628,7 @@ void TattooJournal::highlightJournalControls(bool slamIt) {
color = (_selector == JH_SAVE) ? COMMAND_HIGHLIGHTED : INFO_TOP;
else
color = INFO_BOTTOM;
- screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5),
+ screen.gPrint(Common::Point(xp - screen.stringWidth(FIXED(SaveJournal)) / 2, r.top + 5),
color, "%s", FIXED(SaveJournal));
// Draw the horizontal scrollbar
@@ -701,7 +701,7 @@ void TattooJournal::drawScrollBar() {
raised = _selector != JH_SCROLL_LEFT;
screen._backBuffer1.fillRect(Common::Rect(r.left, r.top + screen.fontHeight() + 12, r.left + BUTTON_SIZE,
r.top + screen.fontHeight() + BUTTON_SIZE + 9), INFO_MIDDLE);
- ui.drawDialogRect(screen._backBuffer1, Common::Rect(r.left + 3, r.top + screen.fontHeight() + 10, r.left + 3 + BUTTON_SIZE,
+ ui.drawDialogRect(screen._backBuffer1, Common::Rect(r.left + 3, r.top + screen.fontHeight() + 10, r.left + 3 + BUTTON_SIZE,
r.top + screen.fontHeight() + 10 + BUTTON_SIZE), raised);
color = (_page > 1) ? INFO_BOTTOM + 2 : INFO_BOTTOM;
@@ -716,15 +716,15 @@ void TattooJournal::drawScrollBar() {
// Draw the Scroll Right button
raised = _selector != JH_SCROLL_RIGHT;
- screen._backBuffer1.fillRect(Common::Rect(r.right - BUTTON_SIZE - 1, r.top + screen.fontHeight() + 12,
+ screen._backBuffer1.fillRect(Common::Rect(r.right - BUTTON_SIZE - 1, r.top + screen.fontHeight() + 12,
r.right - 5, r.top + screen.fontHeight() + BUTTON_SIZE + 9), INFO_MIDDLE);
ui.drawDialogRect(screen._backBuffer1, Common::Rect(r.right - BUTTON_SIZE - 3, r.top + screen.fontHeight() + 10, r.right - 3,
r.top + screen.fontHeight() + BUTTON_SIZE + 9), raised);
color = _down ? INFO_BOTTOM + 2 : INFO_BOTTOM;
- screen._backBuffer1.vLine(r.right - 1 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2,
+ screen._backBuffer1.vLine(r.right - 1 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2,
r.top + screen.fontHeight() + 10 + BUTTON_SIZE / 2, color);
- screen._backBuffer1.vLine(r.right - 2 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 9 + BUTTON_SIZE / 2,
+ screen._backBuffer1.vLine(r.right - 2 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 9 + BUTTON_SIZE / 2,
r.top + screen.fontHeight() + 11 + BUTTON_SIZE / 2, color);
screen._backBuffer1.vLine(r.right - 3 - BUTTON_SIZE + BUTTON_SIZE / 2, r.top + screen.fontHeight() + 8 + BUTTON_SIZE / 2,
r.top + screen.fontHeight() + 12 + BUTTON_SIZE / 2, color);
@@ -776,14 +776,14 @@ int TattooJournal::getFindName(bool printError) {
drawControls(1);
disableControls();
-
+
// Backup the area under the text entry
Surface bgSurface(r.width() - 6, screen.fontHeight());
- bgSurface.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(r.left + 3, cursorY,
+ bgSurface.SHblitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(r.left + 3, cursorY,
r.right - 3, cursorY + screen.fontHeight()));
if (printError) {
- screen.gPrint(Common::Point(r.left + (r.width() - screen.stringWidth(FIXED(TextNotFound))) / 2, cursorY),
+ screen.gPrint(Common::Point(r.left + (r.width() - screen.stringWidth(FIXED(TextNotFound))) / 2, cursorY),
INFO_TOP, "%s", FIXED(TextNotFound));
} else {
// If there was a name already entered, copy it to name and display it
@@ -810,7 +810,7 @@ int TattooJournal::getFindName(bool printError) {
events.clearEvents();
// Restore the text background
- screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left, cursorY));
+ screen._backBuffer1.SHblitFrom(bgSurface, Common::Point(r.left, cursorY));
// If there was a name already entered, copy it to name and display it
if (!_find.empty()) {
@@ -846,7 +846,7 @@ int TattooJournal::getFindName(bool printError) {
}
else {
// Erase cursor by restoring background and writing current text
- screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left + 3, cursorY));
+ screen._backBuffer1.SHblitFrom(bgSurface, Common::Point(r.left + 3, cursorY));
screen.gPrint(Common::Point(r.left + screen.widestChar() + 3, cursorY), COMMAND_HIGHLIGHTED, "%s", name.c_str());
screen.slamArea(r.left + 3, cursorY, r.width() - 3, screen.fontHeight());
}
@@ -912,7 +912,7 @@ int TattooJournal::getFindName(bool printError) {
}
// Redraw the text
- screen._backBuffer1.blitFrom(bgSurface, Common::Point(r.left + 3, cursorY));
+ screen._backBuffer1.SHblitFrom(bgSurface, Common::Point(r.left + 3, cursorY));
screen.gPrint(Common::Point(r.left + screen.widestChar() + 3, cursorY), COMMAND_HIGHLIGHTED,
"%s", name.c_str());
screen.slamArea(r.left + 3, cursorY, r.right - 3, screen.fontHeight());
@@ -977,7 +977,7 @@ void TattooJournal::saveJournal() {
int line = 0;
// Copy all of the talk files entries into one big string
- do {
+ do {
if (_lines[line].hasPrefix("@")) {
text += Common::String(_lines[line].c_str() + 1);
if ((line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@"))
@@ -992,7 +992,7 @@ void TattooJournal::saveJournal() {
// which show up as a blank line with the next line starting
// with a '@'. We have to add a line break here because the '@' handler
// previously assumes that they're always following a blank line
-
+
if ((_lines[line].empty() || _lines[line] == " ")
&& (line + 1) < (int)_lines.size() && _lines[line + 1].hasPrefix("@"))
text += "\n";
@@ -1005,7 +1005,7 @@ void TattooJournal::saveJournal() {
do {
if (text.size() > 80) {
const char *msgP = text.c_str() + 80;
-
+
if (Common::String(text.c_str(), msgP).contains("\n")) {
// The 80 characters contain a carriage return,
// so we can print out that line
@@ -1013,7 +1013,7 @@ void TattooJournal::saveJournal() {
file->writeString(Common::String(text.c_str(), cr));
text = Common::String(cr + 1);
} else {
- // Move backwards to find a word break
+ // Move backwards to find a word break
while (*msgP != ' ')
--msgP;
diff --git a/engines/sherlock/tattoo/tattoo_map.cpp b/engines/sherlock/tattoo/tattoo_map.cpp
index 4c7e8c8fef..23e8bd9739 100644
--- a/engines/sherlock/tattoo/tattoo_map.cpp
+++ b/engines/sherlock/tattoo/tattoo_map.cpp
@@ -105,7 +105,8 @@ int TattooMap::show() {
// Load the map image and draw it to the back buffer
ImageFile *map = new ImageFile("map.vgs");
screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2);
- screen._backBuffer1.blitFrom((*map)[0], Common::Point(0, 0));
+ screen._backBuffer1.SHblitFrom((*map)[0], Common::Point(0, 0));
+ screen.activateBackBuffer1();
delete map;
screen.clear();
@@ -114,7 +115,7 @@ int TattooMap::show() {
// Copy the map drawn in the back buffer to the secondary back buffer
screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH * 2, SHERLOCK_SCREEN_HEIGHT * 2);
- screen._backBuffer2.blitFrom(screen._backBuffer1);
+ screen._backBuffer2.SHblitFrom(screen._backBuffer1);
// Display the built map to the screen
screen.slamArea(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
@@ -148,12 +149,12 @@ int TattooMap::show() {
if (_targetScroll.x < 0)
_targetScroll.x = 0;
- if ((_targetScroll.x + SHERLOCK_SCREEN_WIDTH) > screen._backBuffer1.w())
- _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH;
+ if ((_targetScroll.x + SHERLOCK_SCREEN_WIDTH) > screen._backBuffer1.width())
+ _targetScroll.x = screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH;
if (_targetScroll.y < 0)
_targetScroll.y = 0;
- if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.h())
- _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT;
+ if ((_targetScroll.y + SHERLOCK_SCREEN_HEIGHT) > screen._backBuffer1.height())
+ _targetScroll.y = screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT;
// Check the keyboard
if (events.kbHit()) {
@@ -166,8 +167,8 @@ int TattooMap::show() {
break;
case Common::KEYCODE_END:
- _targetScroll.x = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH;
- _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT;
+ _targetScroll.x = screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH;
+ _targetScroll.y = screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT;
break;
case Common::KEYCODE_PAGEUP:
@@ -178,8 +179,8 @@ int TattooMap::show() {
case Common::KEYCODE_PAGEDOWN:
_targetScroll.y += SHERLOCK_SCREEN_HEIGHT;
- if (_targetScroll.y > (screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT))
- _targetScroll.y = screen._backBuffer1.h() - SHERLOCK_SCREEN_HEIGHT;
+ if (_targetScroll.y > (screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT))
+ _targetScroll.y = screen._backBuffer1.height() - SHERLOCK_SCREEN_HEIGHT;
break;
case Common::KEYCODE_SPACE:
@@ -224,6 +225,7 @@ int TattooMap::show() {
// Reset the back buffers back to standard size
screen._backBuffer1.create(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
screen._backBuffer2.create(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
+ screen.activateBackBuffer1();
return result;
}
@@ -304,7 +306,7 @@ void TattooMap::drawMapIcons() {
if (_data[idx]._iconNum != -1 && _vm->readFlags(idx + 1)) {
MapEntry &mapEntry = _data[idx];
ImageFrame &img = (*_iconImages)[mapEntry._iconNum];
- screen._backBuffer1.transBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2,
+ screen._backBuffer1.SHtransBlitFrom(img._frame, Common::Point(mapEntry.x - img._width / 2,
mapEntry.y - img._height / 2));
}
}
@@ -355,10 +357,10 @@ void TattooMap::restoreArea(const Common::Rect &bounds) {
Screen &screen = *_vm->_screen;
Common::Rect r = bounds;
- r.clip(Common::Rect(0, 0, screen._backBuffer1.w(), screen._backBuffer1.h()));
+ r.clip(Common::Rect(0, 0, screen._backBuffer1.width(), screen._backBuffer1.height()));
if (!r.isEmpty())
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r);
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(r.left, r.top), r);
}
void TattooMap::showCloseUp(int closeUpNum) {
@@ -407,7 +409,7 @@ void TattooMap::showCloseUp(int closeUpNum) {
screen._currentScroll.y + closeUp.y / 100 - picSize.y / 2);
restoreArea(oldBounds);
- screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal);
+ screen._backBuffer1.SHtransBlitFrom(pic[0], pt, false, 0, scaleVal);
screen.slamRect(oldBounds);
screen.slamArea(pt.x, pt.y, picSize.x, picSize.y);
@@ -426,7 +428,7 @@ void TattooMap::showCloseUp(int closeUpNum) {
screen._currentScroll.y + SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2 + pic[0]._height);
restoreArea(oldBounds);
- screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top));
+ screen._backBuffer1.SHtransBlitFrom(pic[0], Common::Point(r.left, r.top));
screen.slamRect(oldBounds);
screen.slamRect(r);
diff --git a/engines/sherlock/tattoo/tattoo_people.cpp b/engines/sherlock/tattoo/tattoo_people.cpp
index b83a977a77..65cc283b66 100644
--- a/engines/sherlock/tattoo/tattoo_people.cpp
+++ b/engines/sherlock/tattoo/tattoo_people.cpp
@@ -1042,7 +1042,7 @@ void TattooPerson::walkHolmesToNPC() {
holmes._walkDest.x = MAX(_position.x / FIXED_INT_MULTIPLIER - imgFrame.sDrawXSize(scaleVal), 0);
} else {
holmes._walkDest.x = MIN(_position.x / FIXED_INT_MULTIPLIER + imgFrame.sDrawXSize(scaleVal) * 2,
- screen._backBuffer1.w() - 1);
+ screen._backBuffer1.width() - 1);
}
// See where Holmes is with respect to the NPC (y coords)
@@ -1168,7 +1168,7 @@ void TattooPerson::centerScreenOnPerson() {
TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;
ui._targetScroll.x = CLIP(_position.x / FIXED_INT_MULTIPLIER - SHERLOCK_SCREEN_WIDTH / 2,
- 0, screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH);
+ 0, screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH);
screen._currentScroll = ui._targetScroll;
// Reset the default look position to the center of the screen
@@ -1478,7 +1478,7 @@ const Common::Point TattooPeople::restrictToZone(int zoneId, const Common::Point
Screen &screen = *_vm->_screen;
Common::Rect &r = scene._zones[zoneId];
- if (destPos.x < 0 || destPos.x > screen._backBuffer1.w())
+ if (destPos.x < 0 || destPos.x > screen._backBuffer1.width())
return destPos;
else if (destPos.y < r.top && r.left < destPos.x && destPos.x < r.right)
return Common::Point(destPos.x, r.top);
diff --git a/engines/sherlock/tattoo/tattoo_people.h b/engines/sherlock/tattoo/tattoo_people.h
index e0d53c67dd..c844d86e19 100644
--- a/engines/sherlock/tattoo/tattoo_people.h
+++ b/engines/sherlock/tattoo/tattoo_people.h
@@ -273,9 +273,8 @@ public:
virtual void setListenSequence(int speaker, int sequenceNum = 1);
};
-} // End of namespace Scalpel
+} // End of namespace Tattoo
} // End of namespace Sherlock
-
#endif
diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp
index 27f37665dc..00015cb189 100644
--- a/engines/sherlock/tattoo/tattoo_scene.cpp
+++ b/engines/sherlock/tattoo/tattoo_scene.cpp
@@ -141,15 +141,15 @@ void TattooScene::drawAllShapes() {
if (obj._type == ACTIVE_BG_SHAPE && obj._misc == BEHIND) {
if (obj._quickDraw && obj._scaleVal == SCALE_THRESHOLD)
- screen._backBuffer1.blitFrom(*obj._imageFrame, obj._position);
+ screen._backBuffer1.SHblitFrom(*obj._imageFrame, obj._position);
else
- screen._backBuffer1.transBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal);
+ screen._backBuffer1.SHtransBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal);
}
}
// Draw the animation if it is behind the person
if (_activeCAnim.active() && _activeCAnim._zPlacement == BEHIND)
- screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position,
+ screen._backBuffer1.SHtransBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position,
(_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal);
screen.resetDisplayBounds();
@@ -194,13 +194,13 @@ void TattooScene::drawAllShapes() {
if (se._shape) {
// it's a bg shape
if (se._shape->_quickDraw && se._shape->_scaleVal == SCALE_THRESHOLD)
- screen._backBuffer1.blitFrom(*se._shape->_imageFrame, se._shape->_position);
+ screen._backBuffer1.SHblitFrom(*se._shape->_imageFrame, se._shape->_position);
else
- screen._backBuffer1.transBlitFrom(*se._shape->_imageFrame, se._shape->_position,
+ screen._backBuffer1.SHtransBlitFrom(*se._shape->_imageFrame, se._shape->_position,
se._shape->_flags & OBJ_FLIPPED, 0, se._shape->_scaleVal);
} else if (se._isAnimation) {
// It's an active animation
- screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position,
+ screen._backBuffer1.SHtransBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position,
(_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal);
} else {
// Drawing person
@@ -212,7 +212,7 @@ void TattooScene::drawAllShapes() {
if (p._tempScaleVal == SCALE_THRESHOLD) {
p._tempX += adjust.x;
- screen._backBuffer1.transBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
+ screen._backBuffer1.SHtransBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
- p.frameHeight() - adjust.y), p._walkSequences[p._sequenceNumber]._horizFlip, 0, p._tempScaleVal);
} else {
if (adjust.x) {
@@ -242,7 +242,7 @@ void TattooScene::drawAllShapes() {
++adjust.y;
}
- screen._backBuffer1.transBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
+ screen._backBuffer1.SHtransBlitFrom(*p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
- p._imageFrame->sDrawYSize(p._tempScaleVal) - adjust.y), p._walkSequences[p._sequenceNumber]._horizFlip, 0, p._tempScaleVal);
}
}
@@ -255,15 +255,15 @@ void TattooScene::drawAllShapes() {
if (obj._type == ACTIVE_BG_SHAPE && obj._misc == FORWARD) {
if (obj._quickDraw && obj._scaleVal == SCALE_THRESHOLD)
- screen._backBuffer1.blitFrom(*obj._imageFrame, obj._position);
+ screen._backBuffer1.SHblitFrom(*obj._imageFrame, obj._position);
else
- screen._backBuffer1.transBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal);
+ screen._backBuffer1.SHtransBlitFrom(*obj._imageFrame, obj._position, obj._flags & OBJ_FLIPPED, 0, obj._scaleVal);
}
}
// Draw the canimation if it is set as FORWARD
if (_activeCAnim.active() && _activeCAnim._zPlacement == FORWARD)
- screen._backBuffer1.transBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal);
+ screen._backBuffer1.SHtransBlitFrom(_activeCAnim._imageFrame, _activeCAnim._position, (_activeCAnim._flags & 4) >> 1, 0, _activeCAnim._scaleVal);
// Draw all NO_SHAPE shapes which have their flag bits clear
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
diff --git a/engines/sherlock/tattoo/tattoo_screen.cpp b/engines/sherlock/tattoo/tattoo_screen.cpp
new file mode 100644
index 0000000000..159060b19e
--- /dev/null
+++ b/engines/sherlock/tattoo/tattoo_screen.cpp
@@ -0,0 +1,38 @@
+/* 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.
+ *
+ */
+
+#include "sherlock/tattoo/tattoo_screen.h"
+#include "sherlock/tattoo/tattoo.h"
+
+namespace Sherlock {
+
+namespace Tattoo {
+
+TattooScreen::TattooScreen(SherlockEngine *vm) : Screen(vm) {
+ _backBuffer1.create(640, 480);
+ _backBuffer2.create(640, 480);
+ activateBackBuffer1();
+}
+
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
diff --git a/engines/sci/graphics/paint.h b/engines/sherlock/tattoo/tattoo_screen.h
index b2277131d5..b55e9bb0dd 100644
--- a/engines/sci/graphics/paint.h
+++ b/engines/sherlock/tattoo/tattoo_screen.h
@@ -20,20 +20,25 @@
*
*/
-#ifndef SCI_GRAPHICS_PAINT_H
-#define SCI_GRAPHICS_PAINT_H
+#ifndef SHERLOCK_TATTOO_SCREEN_H
+#define SHERLOCK_TATTOO_SCREEN_H
-namespace Sci {
+#include "sherlock/screen.h"
-class GfxPaint {
-public:
- GfxPaint();
- virtual ~GfxPaint();
+namespace Sherlock {
+
+class SherlockEngine;
+
+namespace Tattoo {
- virtual void kernelDrawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo);
- virtual void kernelGraphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control);
+class TattooScreen : public Screen {
+public:
+ TattooScreen(SherlockEngine *vm);
+ virtual ~TattooScreen() {}
};
-} // End of namespace Sci
+} // End of namespace Tattoo
+
+} // End of namespace Sherlock
#endif
diff --git a/engines/sherlock/tattoo/tattoo_user_interface.cpp b/engines/sherlock/tattoo/tattoo_user_interface.cpp
index ee028f89c2..677a662535 100644
--- a/engines/sherlock/tattoo/tattoo_user_interface.cpp
+++ b/engines/sherlock/tattoo/tattoo_user_interface.cpp
@@ -72,7 +72,7 @@ TattooUserInterface::~TattooUserInterface() {
void TattooUserInterface::initScrollVars() {
Screen &screen = *_vm->_screen;
- _scrollSize = screen._backBuffer1.w() - SHERLOCK_SCREEN_WIDTH;
+ _scrollSize = screen._backBuffer1.width() - SHERLOCK_SCREEN_WIDTH;
_targetScroll = Common::Point(0, 0);
screen._currentScroll = Common::Point(0, 0);
}
@@ -233,7 +233,7 @@ void TattooUserInterface::doJournal() {
Common::copy(&lookupTable1[0], &lookupTable1[PALETTE_COUNT], &_lookupTable1[0]);
// Restore the scene
- screen._backBuffer1.blitFrom(screen._backBuffer2);
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2);
scene.updateBackground();
screen.slamArea(screen._currentScroll.x, screen._currentScroll.y, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
}
@@ -727,7 +727,7 @@ void TattooUserInterface::doBgAnimEraseBackground() {
if (_mask != nullptr) {
// Since a mask is active, restore the screen from the secondary back buffer prior to applying the mask
- screen._backBuffer1.blitFrom(screen._backBuffer2, screen._currentScroll, Common::Rect(screen._currentScroll.x, 0,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, screen._currentScroll, Common::Rect(screen._currentScroll.x, 0,
screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
switch (scene._currentScene) {
@@ -757,7 +757,7 @@ void TattooUserInterface::doBgAnimEraseBackground() {
case 53:
if (++_maskCounter == 2) {
_maskCounter = 0;
- if (++_maskOffset.x == screen._backBuffer1.w())
+ if (++_maskOffset.x == screen._backBuffer1.width())
_maskOffset.x = 0;
}
break;
@@ -779,7 +779,7 @@ void TattooUserInterface::doBgAnimEraseBackground() {
if ((obj._type == ACTIVE_BG_SHAPE && (obj._maxFrames > 1 || obj._delta.x != 0 || obj._delta.y != 0)) ||
obj._type == HIDE_SHAPE || obj._type == REMOVE)
- screen._backBuffer1.blitFrom(screen._backBuffer2, obj._oldPosition,
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, obj._oldPosition,
Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
obj._oldPosition.y + obj._oldSize.y));
}
@@ -793,7 +793,7 @@ void TattooUserInterface::doBgAnimEraseBackground() {
Object &obj = scene._bgShapes[idx];
if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
- screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
obj._oldPosition = obj._position;
obj._oldSize = obj._noShapeSize;
@@ -870,7 +870,7 @@ void TattooUserInterface::maskArea(Common::SeekableReadStream &mask, const Commo
int pixel, len, xp, yp;
for (yp = 0; yp < ySize; ++yp) {
- byte *ptr = bb1.getBasePtr(pt.x, pt.y + yp);
+ byte *ptr = (byte *)bb1.getBasePtr(pt.x, pt.y + yp);
for (xp = 0; xp < xSize;) {
// The mask data consists of pairs of pixel/lengths, where all non-zero pixels means that the
@@ -893,7 +893,7 @@ void TattooUserInterface::makeBGArea(const Common::Rect &r) {
Screen &screen = *_vm->_screen;
for (int yp = r.top; yp < r.bottom; ++yp) {
- byte *ptr = screen._backBuffer1.getBasePtr(r.left, yp);
+ byte *ptr = (byte *)screen._backBuffer1.getBasePtr(r.left, yp);
for (int xp = r.left; xp < r.right; ++xp, ++ptr)
*ptr = _lookupTable[*ptr];
diff --git a/engines/sherlock/tattoo/widget_base.cpp b/engines/sherlock/tattoo/widget_base.cpp
index 8f0649130a..a35f4e5d74 100644
--- a/engines/sherlock/tattoo/widget_base.cpp
+++ b/engines/sherlock/tattoo/widget_base.cpp
@@ -88,7 +88,7 @@ void WidgetBase::erase() {
if (_oldBounds.width() > 0) {
// Restore the affected area from the secondary back buffer into the first one, and then copy to screen
- screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds);
+ screen._backBuffer1.SHblitFrom(screen._backBuffer2, Common::Point(_oldBounds.left, _oldBounds.top), _oldBounds);
screen.slamRect(_oldBounds);
// Reset the old bounds so it won't be erased again
@@ -111,7 +111,7 @@ void WidgetBase::draw() {
drawBackground();
// Draw the widget onto the back buffer and then slam it to the screen
- screen._backBuffer1.transBlitFrom(_surface, Common::Point(_bounds.left, _bounds.top));
+ screen._backBuffer1.SHtransBlitFrom(_surface, Common::Point(_bounds.left, _bounds.top));
screen.slamRect(_bounds);
// Store a copy of the drawn area for later erasing
@@ -183,8 +183,8 @@ void WidgetBase::restrictToScreen() {
_bounds.moveTo(_bounds.left, 0);
if (_bounds.right > (screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH))
_bounds.moveTo(screen._currentScroll.x + SHERLOCK_SCREEN_WIDTH - _bounds.width(), _bounds.top);
- if (_bounds.bottom > screen._backBuffer1.h())
- _bounds.moveTo(_bounds.left, screen._backBuffer1.h() - _bounds.height());
+ if (_bounds.bottom > screen._backBuffer1.height())
+ _bounds.moveTo(_bounds.left, screen._backBuffer1.height() - _bounds.height());
}
void WidgetBase::makeInfoArea(Surface &s) {
@@ -192,30 +192,30 @@ void WidgetBase::makeInfoArea(Surface &s) {
ImageFile &images = *ui._interfaceImages;
// Draw the four corners of the Info Box
- s.transBlitFrom(images[0], Common::Point(0, 0));
- s.transBlitFrom(images[1], Common::Point(s.w() - images[1]._width, 0));
- s.transBlitFrom(images[2], Common::Point(0, s.h() - images[2]._height));
- s.transBlitFrom(images[3], Common::Point(s.w() - images[3]._width, s.h()));
+ s.SHtransBlitFrom(images[0], Common::Point(0, 0));
+ s.SHtransBlitFrom(images[1], Common::Point(s.width() - images[1]._width, 0));
+ s.SHtransBlitFrom(images[2], Common::Point(0, s.height() - images[2]._height));
+ s.SHtransBlitFrom(images[3], Common::Point(s.width() - images[3]._width, s.height()));
// Draw the top of the Info Box
- s.hLine(images[0]._width, 0, s.w() - images[1]._width, INFO_TOP);
- s.hLine(images[0]._width, 1, s.w() - images[1]._width, INFO_MIDDLE);
- s.hLine(images[0]._width, 2, s.w() - images[1]._width, INFO_BOTTOM);
+ s.hLine(images[0]._width, 0, s.width() - images[1]._width, INFO_TOP);
+ s.hLine(images[0]._width, 1, s.width() - images[1]._width, INFO_MIDDLE);
+ s.hLine(images[0]._width, 2, s.width() - images[1]._width, INFO_BOTTOM);
// Draw the bottom of the Info Box
- s.hLine(images[0]._width, s.h()- 3, s.w() - images[1]._width, INFO_TOP);
- s.hLine(images[0]._width, s.h()- 2, s.w() - images[1]._width, INFO_MIDDLE);
- s.hLine(images[0]._width, s.h()- 1, s.w() - images[1]._width, INFO_BOTTOM);
+ s.hLine(images[0]._width, s.height()- 3, s.width() - images[1]._width, INFO_TOP);
+ s.hLine(images[0]._width, s.height()- 2, s.width() - images[1]._width, INFO_MIDDLE);
+ s.hLine(images[0]._width, s.height()- 1, s.width() - images[1]._width, INFO_BOTTOM);
// Draw the left Side of the Info Box
- s.vLine(0, images[0]._height, s.h()- images[2]._height, INFO_TOP);
- s.vLine(1, images[0]._height, s.h()- images[2]._height, INFO_MIDDLE);
- s.vLine(2, images[0]._height, s.h()- images[2]._height, INFO_BOTTOM);
+ s.vLine(0, images[0]._height, s.height()- images[2]._height, INFO_TOP);
+ s.vLine(1, images[0]._height, s.height()- images[2]._height, INFO_MIDDLE);
+ s.vLine(2, images[0]._height, s.height()- images[2]._height, INFO_BOTTOM);
// Draw the right Side of the Info Box
- s.vLine(s.w() - 3, images[0]._height, s.h()- images[2]._height, INFO_TOP);
- s.vLine(s.w() - 2, images[0]._height, s.h()- images[2]._height, INFO_MIDDLE);
- s.vLine(s.w() - 1, images[0]._height, s.h()- images[2]._height, INFO_BOTTOM);
+ s.vLine(s.width() - 3, images[0]._height, s.height()- images[2]._height, INFO_TOP);
+ s.vLine(s.width() - 2, images[0]._height, s.height()- images[2]._height, INFO_MIDDLE);
+ s.vLine(s.width() - 1, images[0]._height, s.height()- images[2]._height, INFO_BOTTOM);
}
void WidgetBase::makeInfoArea() {
diff --git a/engines/sherlock/tattoo/widget_credits.cpp b/engines/sherlock/tattoo/widget_credits.cpp
index 2b37dd304b..1c878daaf6 100644
--- a/engines/sherlock/tattoo/widget_credits.cpp
+++ b/engines/sherlock/tattoo/widget_credits.cpp
@@ -37,7 +37,7 @@ void WidgetCredits::initCredits() {
Screen &screen = *_vm->_screen;
Common::SeekableReadStream *stream = res.load("credits.txt");
int spacing = screen.fontHeight() * 2;
- int yp = screen.h();
+ int yp = screen.height();
_creditsActive = true;
_creditLines.clear();
@@ -60,7 +60,7 @@ void WidgetCredits::initCredits() {
} else {
int width = screen.stringWidth(line) + 2;
- _creditLines.push_back(CreditLine(line, Common::Point((screen.w() - width) / 2 + 1, yp), width));
+ _creditLines.push_back(CreditLine(line, Common::Point((screen.width() - width) / 2 + 1, yp), width));
yp += spacing;
}
}
@@ -120,10 +120,10 @@ void WidgetCredits::close() {
void WidgetCredits::drawCredits() {
Screen &screen = *_vm->_screen;
- Common::Rect screenRect(0, 0, screen.w(), screen.h());
+ Common::Rect screenRect(0, 0, screen.width(), screen.height());
Surface &bb1 = screen._backBuffer1;
- for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < screen.h(); ++idx) {
+ for (uint idx = 0; idx < _creditLines.size() && _creditLines[idx]._position.y < screen.height(); ++idx) {
if (screenRect.contains(_creditLines[idx]._position)) {
if (!_creditLines[idx]._line2.empty()) {
int x1 = _creditLines[idx]._position.x;
@@ -176,7 +176,7 @@ void WidgetCredits::drawCredits() {
void WidgetCredits::blitCredits() {
Screen &screen = *_vm->_screen;
- Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed);
+ Common::Rect screenRect(0, -_creditSpeed, screen.width(), screen.height() + _creditSpeed);
for (uint idx = 0; idx < _creditLines.size(); ++idx) {
if (screenRect.contains(_creditLines[idx]._position)) {
@@ -190,7 +190,7 @@ void WidgetCredits::blitCredits() {
void WidgetCredits::eraseCredits() {
Screen &screen = *_vm->_screen;
- Common::Rect screenRect(0, -_creditSpeed, screen.w(), screen.h() + _creditSpeed);
+ Common::Rect screenRect(0, -_creditSpeed, screen.width(), screen.height() + _creditSpeed);
for (uint idx = 0; idx < _creditLines.size(); ++idx) {
if (screenRect.contains(_creditLines[idx]._position)) {
diff --git a/engines/sherlock/tattoo/widget_files.cpp b/engines/sherlock/tattoo/widget_files.cpp
index ff8cb83dca..7666e81480 100644
--- a/engines/sherlock/tattoo/widget_files.cpp
+++ b/engines/sherlock/tattoo/widget_files.cpp
@@ -107,36 +107,36 @@ void WidgetFiles::render(FilesRenderMode mode) {
byte color;
if (mode == RENDER_ALL) {
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
makeInfoArea();
switch (_fileMode) {
case SAVEMODE_LOAD:
_surface.writeString(FIXED(LoadGame),
- Common::Point((_surface.w() - _surface.stringWidth(FIXED(LoadGame))) / 2, 5), INFO_TOP);
+ Common::Point((_surface.width() - _surface.stringWidth(FIXED(LoadGame))) / 2, 5), INFO_TOP);
break;
case SAVEMODE_SAVE:
_surface.writeString(FIXED(SaveGame),
- Common::Point((_surface.w() - _surface.stringWidth(FIXED(SaveGame))) / 2, 5), INFO_TOP);
+ Common::Point((_surface.width() - _surface.stringWidth(FIXED(SaveGame))) / 2, 5), INFO_TOP);
break;
default:
break;
}
- _surface.hLine(3, _surface.fontHeight() + 7, _surface.w() - 4, INFO_TOP);
- _surface.hLine(3, _surface.fontHeight() + 8, _surface.w() - 4, INFO_MIDDLE);
- _surface.hLine(3, _surface.fontHeight() + 9, _surface.w() - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 6));
- _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, _surface.fontHeight() + 6));
+ _surface.hLine(3, _surface.fontHeight() + 7, _surface.width() - 4, INFO_TOP);
+ _surface.hLine(3, _surface.fontHeight() + 8, _surface.width() - 4, INFO_MIDDLE);
+ _surface.hLine(3, _surface.fontHeight() + 9, _surface.width() - 4, INFO_BOTTOM);
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 6));
+ _surface.SHtransBlitFrom(images[5], Common::Point(_surface.width() - images[5]._width, _surface.fontHeight() + 6));
- int xp = _surface.w() - BUTTON_SIZE - 6;
+ int xp = _surface.width() - BUTTON_SIZE - 6;
_surface.vLine(xp, _surface.fontHeight() + 10, _bounds.height() - 4, INFO_TOP);
_surface.vLine(xp + 1, _surface.fontHeight() + 10, _bounds.height() - 4, INFO_MIDDLE);
_surface.vLine(xp + 2, _surface.fontHeight() + 10, _bounds.height() - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[6], Common::Point(xp - 1, _surface.fontHeight() + 8));
- _surface.transBlitFrom(images[7], Common::Point(xp - 1, _bounds.height() - 4));
+ _surface.SHtransBlitFrom(images[6], Common::Point(xp - 1, _surface.fontHeight() + 8));
+ _surface.SHtransBlitFrom(images[7], Common::Point(xp - 1, _bounds.height() - 4));
}
int xp = _surface.stringWidth("00.") + _surface.widestChar() + 5;
@@ -149,7 +149,7 @@ void WidgetFiles::render(FilesRenderMode mode) {
color = INFO_TOP;
if (mode == RENDER_NAMES_AND_SCROLLBAR)
- _surface.fillRect(Common::Rect(4, yp, _surface.w() - BUTTON_SIZE - 9, yp + _surface.fontHeight()), TRANSPARENCY);
+ _surface.fillRect(Common::Rect(4, yp, _surface.width() - BUTTON_SIZE - 9, yp + _surface.fontHeight()), TRANSPARENCY);
Common::String numStr = Common::String::format("%d.", idx + 1);
_surface.writeString(numStr, Common::Point(_surface.widestChar(), yp), color);
@@ -324,7 +324,7 @@ bool WidgetFiles::getFilename() {
filename.setChar(' ', index);
}
- _surface.fillRect(Common::Rect(pt.x, pt.y, _surface.w() - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.fillRect(Common::Rect(pt.x, pt.y, _surface.width() - BUTTON_SIZE - 9, pt.y + _surface.fontHeight() - 1), TRANSPARENCY);
_surface.writeString(filename.c_str() + index, pt, COMMAND_HIGHLIGHTED);
} else if ((keyState.keycode == Common::KEYCODE_LEFT && index > 0)
@@ -387,7 +387,7 @@ bool WidgetFiles::getFilename() {
}
if ((keyState.ascii >= ' ') && (keyState.ascii <= 'z') && (index < 50)) {
- if (pt.x + _surface.charWidth(keyState.ascii) < _surface.w() - BUTTON_SIZE - 20) {
+ if (pt.x + _surface.charWidth(keyState.ascii) < _surface.w - BUTTON_SIZE - 20) {
if (insert)
filename.insertChar(keyState.ascii, index);
else
diff --git a/engines/sherlock/tattoo/widget_foolscap.cpp b/engines/sherlock/tattoo/widget_foolscap.cpp
index c8df71e873..8225946838 100644
--- a/engines/sherlock/tattoo/widget_foolscap.cpp
+++ b/engines/sherlock/tattoo/widget_foolscap.cpp
@@ -103,7 +103,7 @@ void WidgetFoolscap::show() {
// Set up the window background
_surface.create(_bounds.width(), _bounds.height());
- _surface.blitFrom(paperFrame, Common::Point(0, 0));
+ _surface.SHblitFrom(paperFrame, Common::Point(0, 0));
// If they have already solved the puzzle, put the answer on the graphic
if (_vm->readFlags(299)) {
@@ -265,7 +265,7 @@ void WidgetFoolscap::handleKeyboardEvents() {
void WidgetFoolscap::restoreChar() {
Screen &screen = *_vm->_screen;
ImageFrame &bgFrame = (*_images)[0];
- _surface.blitFrom(bgFrame, _cursorPos, Common::Rect(_cursorPos.x, _cursorPos.y,
+ _surface.SHblitFrom(bgFrame, _cursorPos, Common::Rect(_cursorPos.x, _cursorPos.y,
_cursorPos.x + screen.widestChar(), _cursorPos.y + screen.fontHeight()));
}
diff --git a/engines/sherlock/tattoo/widget_inventory.cpp b/engines/sherlock/tattoo/widget_inventory.cpp
index b49e30b30d..9f126cf7a7 100644
--- a/engines/sherlock/tattoo/widget_inventory.cpp
+++ b/engines/sherlock/tattoo/widget_inventory.cpp
@@ -94,7 +94,7 @@ void WidgetInventoryTooltip::setText(const Common::String &str) {
// Allocate a fresh surface for the new string
_bounds = Common::Rect(width, height);
_surface.create(width, height);
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
if (line2.empty()) {
_surface.writeFancyString(str, Common::Point(0, 0), BLACK, INFO_TOP);
@@ -338,7 +338,7 @@ void WidgetInventoryVerbs::load() {
// Create the surface
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
makeInfoArea();
// Draw the Verb commands and the lines separating them
@@ -352,8 +352,8 @@ void WidgetInventoryVerbs::load() {
_surface.vLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 1, _bounds.right - 4, INFO_MIDDLE);
_surface.vLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 2, _bounds.right - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1)));
- _surface.transBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width,
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1)));
+ _surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width,
(_surface.fontHeight() + 7) * (idx + 1) - 1));
}
}
@@ -515,7 +515,7 @@ void WidgetInventory::load(int mode) {
// Redraw the inventory menu on the widget surface
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
// Draw the window background and then the inventory on top of it
makeInfoArea(_surface);
@@ -531,7 +531,7 @@ void WidgetInventory::drawBars() {
_surface.hLine(3, INVENTORY_YSIZE + 3, _bounds.width() - 4, INFO_TOP);
_surface.hLine(3, INVENTORY_YSIZE + 4, _bounds.width() - 4, INFO_MIDDLE);
_surface.hLine(3, INVENTORY_YSIZE + 5, _bounds.width() - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[4], Common::Point(0, INVENTORY_YSIZE + 2));
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, INVENTORY_YSIZE + 2));
for (int idx = 1; idx <= NUM_INVENTORY_SHOWN / 2; ++idx) {
x = idx * (INVENTORY_XSIZE + 3);
@@ -540,13 +540,13 @@ void WidgetInventory::drawBars() {
_surface.vLine(x + 1, 3, _bounds.height() - 4, INFO_MIDDLE);
_surface.vLine(x + 2, 3, _bounds.height() - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[6], Common::Point(x - 1, 1));
- _surface.transBlitFrom(images[7], Common::Point(x - 1, _bounds.height() - 4));
- _surface.transBlitFrom(images[6], Common::Point(x - 1, INVENTORY_YSIZE + 5));
- _surface.transBlitFrom(images[7], Common::Point(x - 1, INVENTORY_YSIZE + 2));
+ _surface.SHtransBlitFrom(images[6], Common::Point(x - 1, 1));
+ _surface.SHtransBlitFrom(images[7], Common::Point(x - 1, _bounds.height() - 4));
+ _surface.SHtransBlitFrom(images[6], Common::Point(x - 1, INVENTORY_YSIZE + 5));
+ _surface.SHtransBlitFrom(images[7], Common::Point(x - 1, INVENTORY_YSIZE + 2));
}
- _surface.hLine(x + 2, INVENTORY_YSIZE + 2, INVENTORY_YSIZE + 8, INFO_BOTTOM);
+ _surface.vLine(x + 2, INVENTORY_YSIZE + 2, INVENTORY_YSIZE + 8, INFO_BOTTOM);
}
void WidgetInventory::drawInventory() {
@@ -566,7 +566,7 @@ void WidgetInventory::drawInventory() {
// Draw the item
if (itemId < inv._holdings) {
ImageFrame &img = (*inv._invShapes[idx])[0];
- _surface.transBlitFrom(img, Common::Point(pt.x + (INVENTORY_XSIZE - img._width) / 2,
+ _surface.SHtransBlitFrom(img, Common::Point(pt.x + (INVENTORY_XSIZE - img._width) / 2,
pt.y + (INVENTORY_YSIZE - img._height) / 2));
}
}
diff --git a/engines/sherlock/tattoo/widget_options.cpp b/engines/sherlock/tattoo/widget_options.cpp
index 92bd10bbf6..81f50f3bc5 100644
--- a/engines/sherlock/tattoo/widget_options.cpp
+++ b/engines/sherlock/tattoo/widget_options.cpp
@@ -257,17 +257,17 @@ void WidgetOptions::render(OptionRenderMode mode) {
// Setup the dialog
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
makeInfoArea();
// Draw the lines separating options in the dialog
int yp = _surface.fontHeight() + 7;
for (int idx = 0; idx < 7; ++idx) {
- _surface.transBlitFrom(images[4], Common::Point(0, yp - 1));
- _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, yp - 1));
- _surface.hLine(3, yp, _surface.w() - 4, INFO_TOP);
- _surface.hLine(3, yp + 1, _surface.w() - 4, INFO_MIDDLE);
- _surface.hLine(3, yp + 2, _surface.w() - 4, INFO_BOTTOM);
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, yp - 1));
+ _surface.SHtransBlitFrom(images[5], Common::Point(_surface.width() - images[5]._width, yp - 1));
+ _surface.hLine(3, yp, _surface.width() - 4, INFO_TOP);
+ _surface.hLine(3, yp + 1, _surface.width() - 4, INFO_MIDDLE);
+ _surface.hLine(3, yp + 2, _surface.width() - 4, INFO_BOTTOM);
yp += _surface.fontHeight() + 7;
if (idx == 1)
@@ -281,7 +281,7 @@ void WidgetOptions::render(OptionRenderMode mode) {
for (int idx = 0, yp = 5; idx < 11; ++idx, yp += _surface.fontHeight() + 7) {
if (mode == OP_ALL || idx == _selector || idx == _oldSelector) {
if (mode == OP_NAMES)
- _surface.fillRect(Common::Rect(4, yp, _surface.w() - 5, yp + _surface.fontHeight() - 1), TRANSPARENCY);
+ _surface.fillRect(Common::Rect(4, yp, _surface.width() - 5, yp + _surface.fontHeight() - 1), TRANSPARENCY);
byte color = (idx == _selector) ? COMMAND_HIGHLIGHTED : INFO_TOP;
Common::String str;
@@ -302,11 +302,11 @@ void WidgetOptions::render(OptionRenderMode mode) {
int num = (_surface.fontHeight() + 4) & 0xfe;
int sliderY = yp + num / 2 - 8;
- _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 5,
+ _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.width() - 5,
sliderY - (num - 6) / 2 + num - 1), TRANSPARENCY);
_surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2,
- _surface.w() - _surface.widestChar() - 1, sliderY + 3), INFO_MIDDLE);
- drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.w() - _surface.widestChar(), sliderY + 6));
+ _surface.width() - _surface.widestChar() - 1, sliderY + 3), INFO_MIDDLE);
+ drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.width() - _surface.widestChar(), sliderY + 6));
_surface.fillRect(Common::Rect(_midiSliderX - 1, sliderY - (num - 6) / 2 + 2,
_midiSliderX + 1, sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE);
@@ -315,7 +315,7 @@ void WidgetOptions::render(OptionRenderMode mode) {
if (_midiSliderX - 4 > _surface.widestChar())
_surface.fillRect(Common::Rect(_midiSliderX - 4, sliderY, _midiSliderX - 4, sliderY + 4), INFO_BOTTOM);
- if (_midiSliderX + 4 < _surface.w() - _surface.widestChar())
+ if (_midiSliderX + 4 < _surface.width() - _surface.widestChar())
_surface.fillRect(Common::Rect(_midiSliderX + 4, sliderY, _midiSliderX + 4, sliderY + 4), INFO_BOTTOM);
break;
}
@@ -332,18 +332,18 @@ void WidgetOptions::render(OptionRenderMode mode) {
int num = (_surface.fontHeight() + 4) & 0xfe;
int sliderY = yp + num / 2 - 8;
- _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.w() - 5,
+ _surface.fillRect(Common::Rect(4, sliderY - (num - 6) / 2, _surface.width() - 5,
sliderY - (num - 6) / 2 + num - 1), TRANSPARENCY);
- _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, _surface.w() - _surface.widestChar() - 1,
+ _surface.fillRect(Common::Rect(_surface.widestChar(), sliderY + 2, _surface.width() - _surface.widestChar() - 1,
sliderY + 3), INFO_MIDDLE);
- drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.w() - _surface.widestChar(), sliderY + 6));
+ drawDialogRect(Common::Rect(_surface.widestChar(), sliderY, _surface.width() - _surface.widestChar(), sliderY + 6));
_surface.fillRect(Common::Rect(_digiSliderX - 1, sliderY - (num - 6) / 2 + 2, _digiSliderX + 1,
sliderY - (num - 6) / 2 + num - 3), INFO_MIDDLE);
drawDialogRect(Common::Rect(_digiSliderX - 3, sliderY - (num - 6) / 2, _digiSliderX + 4,
sliderY - (num - 6) / 2 + num));
if (_digiSliderX - 4 > _surface.widestChar())
_surface.fillRect(Common::Rect(_digiSliderX - 4, sliderY, _digiSliderX - 4, sliderY + 4), INFO_BOTTOM);
- if (_digiSliderX + 4 < _surface.w() - _surface.widestChar())
+ if (_digiSliderX + 4 < _surface.width() - _surface.widestChar())
_surface.fillRect(Common::Rect(_digiSliderX + 4, sliderY, _digiSliderX + 4, sliderY + 4), INFO_BOTTOM);
break;
}
@@ -375,7 +375,7 @@ void WidgetOptions::render(OptionRenderMode mode) {
// Unless we're doing one of the Slider Controls, print the text for the line
if (idx != 3 && idx != 6) {
- int xp = (_surface.w() - _surface.stringWidth(str)) / 2;
+ int xp = (_surface.width() - _surface.stringWidth(str)) / 2;
_surface.writeString(str, Common::Point(xp, yp), color);
}
}
diff --git a/engines/sherlock/tattoo/widget_password.cpp b/engines/sherlock/tattoo/widget_password.cpp
index 57a5e02653..2a2921026d 100644
--- a/engines/sherlock/tattoo/widget_password.cpp
+++ b/engines/sherlock/tattoo/widget_password.cpp
@@ -47,7 +47,7 @@ void WidgetPassword::show() {
// Create the surface
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
makeInfoArea();
// Draw the header area
@@ -55,8 +55,8 @@ void WidgetPassword::show() {
_surface.hLine(3, _surface.fontHeight() + 7, _bounds.width() - 4, INFO_TOP);
_surface.hLine(3, _surface.fontHeight() + 8, _bounds.width() - 4, INFO_MIDDLE);
_surface.hLine(3, _surface.fontHeight() + 9, _bounds.width() - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 7 - 1));
- _surface.transBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, _surface.fontHeight() + 7 - 1));
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, _surface.fontHeight() + 7 - 1));
+ _surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width, _surface.fontHeight() + 7 - 1));
// Set the password entry data
_cursorPos = Common::Point(_surface.widestChar(), _surface.fontHeight() + 12);
diff --git a/engines/sherlock/tattoo/widget_quit.cpp b/engines/sherlock/tattoo/widget_quit.cpp
index f853e7f47f..ea8f2e080c 100644
--- a/engines/sherlock/tattoo/widget_quit.cpp
+++ b/engines/sherlock/tattoo/widget_quit.cpp
@@ -48,22 +48,22 @@ void WidgetQuit::show() {
// Create the surface
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
makeInfoArea();
// Draw the message text
- _surface.writeString(FIXED(AreYouSureYou), Common::Point((_surface.w() - _surface.stringWidth(FIXED(AreYouSureYou))) / 2, 5), INFO_TOP);
- _surface.writeString(FIXED(WishToQuit), Common::Point((_surface.w() - _surface.stringWidth(FIXED(WishToQuit))) / 2,
+ _surface.writeString(FIXED(AreYouSureYou), Common::Point((_surface.width() - _surface.stringWidth(FIXED(AreYouSureYou))) / 2, 5), INFO_TOP);
+ _surface.writeString(FIXED(WishToQuit), Common::Point((_surface.width() - _surface.stringWidth(FIXED(WishToQuit))) / 2,
_surface.fontHeight() + 9), INFO_TOP);
// Draw the horizontal bars seperating the commands and the message
int yp = (_surface.fontHeight() + 4) * 2 + 3;
for (int idx = 0; idx < 2; ++idx) {
- _surface.transBlitFrom(images[4], Common::Point(0, yp - 1));
- _surface.transBlitFrom(images[5], Common::Point(_surface.w() - images[5]._width, yp - 1));
- _surface.hLine(3, yp, _surface.w() - 4, INFO_TOP);
- _surface.hLine(3, yp + 1, _surface.w() - 4, INFO_MIDDLE);
- _surface.hLine(3, yp + 2, _surface.w() - 4, INFO_BOTTOM);
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, yp - 1));
+ _surface.SHtransBlitFrom(images[5], Common::Point(_surface.width() - images[5]._width, yp - 1));
+ _surface.hLine(3, yp, _surface.width() - 4, INFO_TOP);
+ _surface.hLine(3, yp + 1, _surface.width() - 4, INFO_MIDDLE);
+ _surface.hLine(3, yp + 2, _surface.width() - 4, INFO_BOTTOM);
const char *btn = (idx == 0) ? YES : NO;
_surface.writeString(btn, Common::Point((_bounds.width() - _surface.stringWidth(btn)) / 2, yp + 5), INFO_TOP);
@@ -129,11 +129,11 @@ void WidgetQuit::handleEvents() {
if (_select != _oldSelect) {
byte color = (_select == 1) ? COMMAND_HIGHLIGHTED : INFO_TOP;
int yp = (_surface.fontHeight() + 4) * 2 + 8;
- _surface.writeString(FIXED(Yes), Common::Point((_surface.w() - _surface.stringWidth(FIXED(Yes))) / 2, yp), color);
+ _surface.writeString(FIXED(Yes), Common::Point((_surface.width() - _surface.stringWidth(FIXED(Yes))) / 2, yp), color);
color = (_select == 0) ? COMMAND_HIGHLIGHTED : INFO_TOP;
yp += (_surface.fontHeight() + 7);
- _surface.writeString(FIXED(No), Common::Point((_surface.w() - _surface.stringWidth(FIXED(No))) / 2, yp), color);
+ _surface.writeString(FIXED(No), Common::Point((_surface.width() - _surface.stringWidth(FIXED(No))) / 2, yp), color);
}
_oldSelect = _select;
diff --git a/engines/sherlock/tattoo/widget_talk.cpp b/engines/sherlock/tattoo/widget_talk.cpp
index 6e7bde292f..b673f32d31 100644
--- a/engines/sherlock/tattoo/widget_talk.cpp
+++ b/engines/sherlock/tattoo/widget_talk.cpp
@@ -100,7 +100,7 @@ void WidgetTalk::load() {
// Set up the surface
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
// Form the background for the new window
makeInfoArea();
@@ -389,7 +389,7 @@ void WidgetTalk::render(Highlight highlightMode) {
if (highlightMode == HL_NO_HIGHLIGHTING || _statementLines[idx]._num == _selector ||
_statementLines[idx]._num == _oldSelector) {
// Erase the line contents
- _surface.fillRect(Common::Rect(3, yp, _surface.w() - BUTTON_SIZE - 3, yp + _surface.fontHeight()), TRANSPARENCY);
+ _surface.fillRect(Common::Rect(3, yp, _surface.width() - BUTTON_SIZE - 3, yp + _surface.fontHeight()), TRANSPARENCY);
// Different coloring based on whether the option has been previously chosen or not
byte color = (!talk._talkHistory[talk._converseNum][_statementLines[idx]._num]) ?
diff --git a/engines/sherlock/tattoo/widget_text.cpp b/engines/sherlock/tattoo/widget_text.cpp
index d8d229d277..a29cd2700f 100644
--- a/engines/sherlock/tattoo/widget_text.cpp
+++ b/engines/sherlock/tattoo/widget_text.cpp
@@ -166,7 +166,7 @@ void WidgetText::render(const Common::String &str) {
// Allocate a surface for the window
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
// Form the background for the new window
makeInfoArea();
@@ -195,7 +195,7 @@ void WidgetMessage::load(const Common::String &str, int time) {
// Allocate a surface for the window
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
// Form the background for the new window and write the line of text
makeInfoArea();
diff --git a/engines/sherlock/tattoo/widget_tooltip.cpp b/engines/sherlock/tattoo/widget_tooltip.cpp
index b29f45f531..1560cb9a80 100644
--- a/engines/sherlock/tattoo/widget_tooltip.cpp
+++ b/engines/sherlock/tattoo/widget_tooltip.cpp
@@ -47,7 +47,7 @@ void WidgetTooltipBase::draw() {
// Draw the widget directly onto the screen. Unlike other widgets, we don't draw to the back buffer,
// since nothing should be drawing on top of tooltips, so there's no need to store in the back buffer
- screen.transBlitFrom(_surface, Common::Point(_bounds.left - screen._currentScroll.x,
+ screen.SHtransBlitFrom(_surface, Common::Point(_bounds.left - screen._currentScroll.x,
_bounds.top - screen._currentScroll.y));
// Store a copy of the drawn area for later erasing
@@ -126,7 +126,7 @@ void WidgetTooltip::setText(const Common::String &str) {
// Reallocate the text surface with the new size
_surface.create(width, height);
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
if (line2.empty()) {
// Only a single line
diff --git a/engines/sherlock/tattoo/widget_verbs.cpp b/engines/sherlock/tattoo/widget_verbs.cpp
index 499afb2e79..5041888ffb 100644
--- a/engines/sherlock/tattoo/widget_verbs.cpp
+++ b/engines/sherlock/tattoo/widget_verbs.cpp
@@ -127,7 +127,7 @@ void WidgetVerbs::render() {
// Create the drawing surface
_surface.create(_bounds.width(), _bounds.height());
- _surface.fill(TRANSPARENCY);
+ _surface.clear(TRANSPARENCY);
// Draw basic background
makeInfoArea();
@@ -142,8 +142,8 @@ void WidgetVerbs::render() {
_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 1, _bounds.width() - 4, INFO_MIDDLE);
_surface.hLine(3, (_surface.fontHeight() + 7) * (idx + 1) + 2, _bounds.width() - 4, INFO_BOTTOM);
- _surface.transBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1));
- _surface.transBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width,
+ _surface.SHtransBlitFrom(images[4], Common::Point(0, (_surface.fontHeight() + 7) * (idx + 1) - 1));
+ _surface.SHtransBlitFrom(images[5], Common::Point(_bounds.width() - images[5]._width,
(_surface.fontHeight() + 7) * (idx + 1) - 1));
}
}
diff --git a/engines/sky/compact.cpp b/engines/sky/compact.cpp
index ee165934a0..ce62dcb2ae 100644
--- a/engines/sky/compact.cpp
+++ b/engines/sky/compact.cpp
@@ -236,6 +236,8 @@ SkyCompact::SkyCompact() {
for (cnt = 0; cnt < _numSaveIds; cnt++)
_saveIds[cnt] = FROM_LE_16(_saveIds[cnt]);
_resetDataPos = _cptFile->pos();
+
+ checkAndFixOfficerBluntError();
}
SkyCompact::~SkyCompact() {
@@ -257,6 +259,21 @@ SkyCompact::~SkyCompact() {
delete _cptFile;
}
+/* WORKAROUND for bug #2687:
+ The first release of scummvm with externalized, binary compact data has one broken 16 bit reference.
+ When talking to Officer Blunt on ground level while in a crouched position, the game enters an
+ unfinishable state because Blunt jumps into the lake and can no longer be interacted with.
+ This fixes the problem when playing with a broken sky.cpt */
+#define SCUMMVM_BROKEN_TALK_INDEX 158
+void SkyCompact::checkAndFixOfficerBluntError() {
+ // Retrieve the table with the animation ids to use for talking
+ uint16 *talkTable = (uint16*)fetchCpt(CPT_TALK_TABLE_LIST);
+ if (talkTable[SCUMMVM_BROKEN_TALK_INDEX] == ID_SC31_GUARD_TALK) {
+ debug(1, "SKY.CPT with Officer Blunt bug encountered, fixing talk gfx.");
+ talkTable[SCUMMVM_BROKEN_TALK_INDEX] = ID_SC31_GUARD_TALK2;
+ }
+}
+
// needed for some workaround where the engine has to check if it's currently processing joey, for example
bool SkyCompact::cptIsId(Compact *cpt, uint16 id) {
return (cpt == fetchCpt(id));
diff --git a/engines/sky/compact.h b/engines/sky/compact.h
index 0bd5b4943b..86db0ba55b 100644
--- a/engines/sky/compact.h
+++ b/engines/sky/compact.h
@@ -78,6 +78,8 @@ public:
uint16 giveDataListLen(uint16 listNum);
const char *nameForType(uint16 type);
private:
+ void checkAndFixOfficerBluntError();
+
uint16 _numDataLists;
uint16 *_dataListLen;
uint16 *_rawBuf;
diff --git a/engines/sky/control.cpp b/engines/sky/control.cpp
index dfdd765120..a3fef3c0cd 100644
--- a/engines/sky/control.cpp
+++ b/engines/sky/control.cpp
@@ -167,7 +167,7 @@ ControlStatus::~ControlStatus() {
void ControlStatus::setToText(const char *newText) {
char tmpLine[256];
- strcpy(tmpLine, newText);
+ Common::strlcpy(tmpLine, newText, 256);
if (_textData) {
_statusText->flushForRedraw();
free(_textData);
@@ -324,7 +324,11 @@ void Control::initPanel() {
}
void Control::buttonControl(ConResource *pButton) {
- char autoSave[] = "Restore Autosave";
+ char autoSave[50] = "Restore Autosave";
+
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS)
+ strncpy(autoSave, "Zarpyzit/ abtocoxpahehie", 50);
+
if (pButton == NULL) {
free(_textSprite);
_textSprite = NULL;
@@ -398,7 +402,8 @@ void Control::animClick(ConResource *pButton) {
void Control::drawMainPanel() {
memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
_system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
- _controlPanel->drawToScreen(NO_MASK);
+ if (_controlPanel)
+ _controlPanel->drawToScreen(NO_MASK);
_exitButton->drawToScreen(NO_MASK);
_savePanButton->drawToScreen(NO_MASK);
_restorePanButton->drawToScreen(NO_MASK);
@@ -525,8 +530,13 @@ void Control::doControlPanel() {
}
uint16 Control::handleClick(ConResource *pButton) {
- char quitDos[] = "Quit to DOS?";
- char restart[] = "Restart?";
+ char quitDos[50] = "Quit to DOS?";
+ char restart[50] = "Restart?";
+
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
+ strncpy(quitDos, "B[uti b DOC?", 50);
+ strncpy(restart, "Hobaq irpa?", 50);
+ }
switch (pButton->_onClick) {
case DO_NOTHING:
@@ -1328,13 +1338,13 @@ uint16 Control::parseSaveData(uint8 *srcBuf) {
displayMessage(0, "Unknown save file revision (%d)", saveRev);
return RESTORE_FAILED;
} else if (saveRev < OLD_SAVEGAME_TYPE) {
- displayMessage(0, "This savegame version is unsupported.");
+ displayMessage(0, "This saved game version is unsupported.");
return RESTORE_FAILED;
}
LODSD(srcPos, gameVersion);
if (gameVersion != SkyEngine::_systemVars.gameVersion) {
if ((!SkyEngine::isCDVersion()) || (gameVersion < 365)) { // cd versions are compatible
- displayMessage(NULL, "This savegame was created by\n"
+ displayMessage(NULL, "This saved game was created by\n"
"Beneath a Steel Sky v0.0%03d\n"
"It cannot be loaded by this version (v0.0%3d)",
gameVersion, SkyEngine::_systemVars.gameVersion);
@@ -1562,8 +1572,13 @@ void Control::showGameQuitMsg() {
screenData = _skyScreen->giveCurrent();
- _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 0], textBuf1, true, 320, 255);
- _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 1], textBuf2, true, 320, 255);
+ if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
+ _skyText->displayText(_quitTexts[8 * 2 + 0], textBuf1, true, 320, 255);
+ _skyText->displayText(_quitTexts[8 * 2 + 1], textBuf2, true, 320, 255);
+ } else {
+ _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 0], textBuf1, true, 320, 255);
+ _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 1], textBuf2, true, 320, 255);
+ }
uint8 *curLine1 = textBuf1 + sizeof(DataFileHeader);
uint8 *curLine2 = textBuf2 + sizeof(DataFileHeader);
uint8 *targetLine = screenData + GAME_SCREEN_WIDTH * 80;
@@ -1584,7 +1599,7 @@ void Control::showGameQuitMsg() {
free(textBuf2);
}
-char Control::_quitTexts[16][35] = {
+char Control::_quitTexts[18][35] = {
"Game over player one",
"BE VIGILANT",
"Das Spiel ist aus.",
@@ -1600,7 +1615,9 @@ char Control::_quitTexts[16][35] = {
"Fim de jogo para o jogador um",
"BE VIGILANT",
"Game over player one",
- "BE VIGILANT"
+ "BE VIGILANT",
+ "Irpa okohseha, irpok 1",
+ "JYD\x96 JDITELEH"
};
uint8 Control::_crossImg[594] = {
diff --git a/engines/sky/control.h b/engines/sky/control.h
index 44591f299d..2089c74363 100644
--- a/engines/sky/control.h
+++ b/engines/sky/control.h
@@ -292,7 +292,7 @@ private:
ControlStatus *_statusBar;
- static char _quitTexts[16][35];
+ static char _quitTexts[18][35];
static uint8 _crossImg[594];
};
diff --git a/engines/sky/detection.cpp b/engines/sky/detection.cpp
index d85299cc24..4b91f50a61 100644
--- a/engines/sky/detection.cpp
+++ b/engines/sky/detection.cpp
@@ -136,7 +136,7 @@ const ExtraGuiOptions SkyMetaEngine::getExtraGuiOptions(const Common::String &ta
}
GameDescriptor SkyMetaEngine::findGame(const char *gameid) const {
- if (0 == scumm_stricmp(gameid, skySetting.gameid))
+ if (0 == scumm_stricmp(gameid, skySetting.gameId))
return skySetting;
return GameDescriptor();
}
@@ -175,7 +175,7 @@ GameList SkyMetaEngine::detectGames(const Common::FSList &fslist) const {
// Match found, add to list of candidates, then abort inner loop.
// The game detector uses US English by default. We want British
// English to match the recorded voices better.
- GameDescriptor dg(skySetting.gameid, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown);
+ GameDescriptor dg(skySetting.gameId, skySetting.description, Common::UNK_LANG, Common::kPlatformUnknown);
const SkyVersion *sv = skyVersions;
while (sv->dinnerTableEntries) {
if (dinnerTableEntries == sv->dinnerTableEntries &&
diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp
index e1175f9936..ad656ac8df 100644
--- a/engines/sky/logic.cpp
+++ b/engines/sky/logic.cpp
@@ -1717,7 +1717,7 @@ bool Logic::fnSpeakMe(uint32 targetId, uint32 mesgNum, uint32 animNum) {
on other screens, as the lack of speech files for these lines
will cause Foster's speech to be aborted if the timing is bad.
*/
- if (targetId == 0x4039 && animNum == 0x9B && Logic::_scriptVariables[SCREEN] != 38) {
+ if (targetId == ID_DANIELLE && animNum == 0x9B && Logic::_scriptVariables[SCREEN] != 38) {
return false;
}
diff --git a/engines/sky/music/adlibchannel.cpp b/engines/sky/music/adlibchannel.cpp
index c7acb9b6c1..2f44add466 100644
--- a/engines/sky/music/adlibchannel.cpp
+++ b/engines/sky/music/adlibchannel.cpp
@@ -23,7 +23,7 @@
#include "common/endian.h"
#include "common/textconsole.h"
-#include "common/util.h"
+#include "audio/fmopl.h"
#include "sky/music/adlibchannel.h"
#include "sky/sky.h"
diff --git a/engines/sky/music/adlibchannel.h b/engines/sky/music/adlibchannel.h
index 4504e3b570..b190ba27dc 100644
--- a/engines/sky/music/adlibchannel.h
+++ b/engines/sky/music/adlibchannel.h
@@ -24,7 +24,10 @@
#define SKY_MUSIC_ADLIBCHANNEL_H
#include "sky/music/musicbase.h"
-#include "audio/fmopl.h"
+
+namespace OPL {
+class OPL;
+}
namespace Sky {
diff --git a/engines/sky/music/adlibmusic.cpp b/engines/sky/music/adlibmusic.cpp
index be5e7b2353..1a2a91c82a 100644
--- a/engines/sky/music/adlibmusic.cpp
+++ b/engines/sky/music/adlibmusic.cpp
@@ -26,9 +26,13 @@
#include "sky/music/adlibmusic.h"
#include "sky/music/adlibchannel.h"
-#include "audio/mixer.h"
+#include "audio/fmopl.h"
#include "sky/sky.h"
+namespace Audio {
+class Mixer;
+}
+
namespace Sky {
AdLibMusic::AdLibMusic(Audio::Mixer *pMixer, Disk *pDisk) : MusicBase(pMixer, pDisk) {
diff --git a/engines/sky/music/adlibmusic.h b/engines/sky/music/adlibmusic.h
index 7b51f2d3a0..ebfa038848 100644
--- a/engines/sky/music/adlibmusic.h
+++ b/engines/sky/music/adlibmusic.h
@@ -24,7 +24,10 @@
#define SKY_MUSIC_ADLIBMUSIC_H
#include "sky/music/musicbase.h"
-#include "audio/audiostream.h"
+
+namespace Audio {
+class Mixer;
+}
namespace OPL {
class OPL;
diff --git a/engines/sky/sky.h b/engines/sky/sky.h
index 56833004ac..374302b8d3 100644
--- a/engines/sky/sky.h
+++ b/engines/sky/sky.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SKY_H
-#define SKY_H
+#ifndef SKY_SKY_H
+#define SKY_SKY_H
#include "common/error.h"
diff --git a/engines/sky/skydefs.h b/engines/sky/skydefs.h
index 167b7dade2..ed07a5e2cd 100644
--- a/engines/sky/skydefs.h
+++ b/engines/sky/skydefs.h
@@ -45,6 +45,7 @@ namespace Sky {
#define SKY_ITALIAN 5
#define SKY_PORTUGUESE 6
#define SKY_SPANISH 7
+#define SKY_RUSSIAN 8
#define ST_COLLISION_BIT 5
diff --git a/engines/sword1/configure.engine b/engines/sword1/configure.engine
index 0578d176a9..1d17903b69 100644
--- a/engines/sword1/configure.engine
+++ b/engines/sword1/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine sword1 "Broken Sword" yes
+add_engine sword1 "Broken Sword" yes "" "" "highres"
diff --git a/engines/sword1/detection.cpp b/engines/sword1/detection.cpp
index 3eac95cdf2..0edf856125 100644
--- a/engines/sword1/detection.cpp
+++ b/engines/sword1/detection.cpp
@@ -128,17 +128,17 @@ GameList SwordMetaEngine::getSupportedGames() const {
}
GameDescriptor SwordMetaEngine::findGame(const char *gameid) const {
- if (0 == scumm_stricmp(gameid, sword1FullSettings.gameid))
+ if (0 == scumm_stricmp(gameid, sword1FullSettings.gameId))
return sword1FullSettings;
- if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameid))
+ if (0 == scumm_stricmp(gameid, sword1DemoSettings.gameId))
return sword1DemoSettings;
- if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameid))
+ if (0 == scumm_stricmp(gameid, sword1MacFullSettings.gameId))
return sword1MacFullSettings;
- if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameid))
+ if (0 == scumm_stricmp(gameid, sword1MacDemoSettings.gameId))
return sword1MacDemoSettings;
- if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameid))
+ if (0 == scumm_stricmp(gameid, sword1PSXSettings.gameId))
return sword1PSXSettings;
- if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameid))
+ if (0 == scumm_stricmp(gameid, sword1PSXDemoSettings.gameId))
return sword1PSXDemoSettings;
return GameDescriptor();
}
diff --git a/engines/sword1/logic.h b/engines/sword1/logic.h
index 94da2b3a77..005846df16 100644
--- a/engines/sword1/logic.h
+++ b/engines/sword1/logic.h
@@ -28,10 +28,13 @@
#include "sword1/objectman.h"
#include "common/util.h"
#include "common/random.h"
-#include "audio/mixer.h"
class OSystem;
+namespace Audio {
+class Mixer;
+}
+
namespace Sword1 {
#define NON_ZERO_SCRIPT_VARS 95
diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp
index 0a0324a67c..2f8b37d21c 100644
--- a/engines/sword1/resman.cpp
+++ b/engines/sword1/resman.cpp
@@ -327,13 +327,12 @@ Common::File *ResMan::resFile(uint32 id) {
Clu *closeClu = _openCluStart;
_openCluStart = _openCluStart->nextOpen;
- if (closeClu) {
- if (closeClu->file)
- closeClu->file->close();
- delete closeClu->file;
- closeClu->file = NULL;
- closeClu->nextOpen = NULL;
- }
+ if (closeClu->file)
+ closeClu->file->close();
+ delete closeClu->file;
+ closeClu->file = NULL;
+ closeClu->nextOpen = NULL;
+
_openClus--;
}
}
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
index 4deaf06edc..720ed8afc8 100644
--- a/engines/sword1/sound.cpp
+++ b/engines/sword1/sound.cpp
@@ -37,7 +37,6 @@
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/vorbis.h"
-#include "audio/decoders/wave.h"
#include "audio/decoders/xa.h"
namespace Sword1 {
@@ -125,22 +124,29 @@ void Sound::checkSpeechFileEndianness() {
uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
if (sampleSize) {
uint32 size;
+ bool leOk = false, beOk = false;
// Compute average of difference between two consecutive samples for both BE and LE
_bigEndianSpeech = false;
- int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
+ int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size, &leOk);
uint32 maxSamples = size > 2000 ? 2000 : size;
double le_diff = endiannessHeuristicValue(data, size, maxSamples);
delete[] data;
_bigEndianSpeech = true;
- data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
+ data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size, &beOk);
double be_diff = endiannessHeuristicValue(data, size, maxSamples);
delete [] data;
// Set the big endian flag
- _bigEndianSpeech = (be_diff < le_diff);
+ if (leOk && !beOk)
+ _bigEndianSpeech = false;
+ else if (beOk && !leOk)
+ _bigEndianSpeech = true;
+ else
+ _bigEndianSpeech = (be_diff < le_diff);
if (_bigEndianSpeech)
debug(6, "Mac version: using big endian speech file");
else
debug(6, "Mac version: using little endian speech file");
+ debug(8, "Speech decompression memory check: big endian = %s, little endian = %s", beOk ? "good" : "bad", leOk ? "good" : "bad");
debug(8, "Speech endianness heuristic: average = %f for BE and %f for LE (%d samples)", be_diff, le_diff, maxSamples);
}
}
@@ -446,7 +452,7 @@ bool Sound::startSpeech(uint16 roomNo, uint16 localNo) {
return false;
}
-int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
+int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size, bool* ok) {
uint8 *fBuf = (uint8 *)malloc(cSize);
_cowFile.seek(index);
_cowFile.read(fBuf, cSize);
@@ -456,6 +462,8 @@ int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
headerPos++;
if (headerPos < 100) {
+ if (ok != 0)
+ *ok = true;
int32 resSize;
int16 *srcData;
uint32 srcPos;
@@ -508,8 +516,11 @@ int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
srcPos++;
if (length < 0) {
length = -length;
- if (length > samplesLeft)
+ if (length > samplesLeft) {
length = samplesLeft;
+ if (ok != 0)
+ *ok = false;
+ }
int16 value;
if (_bigEndianSpeech) {
value = (int16)SWAP_BYTES_16(*((uint16 *)(srcData + srcPos)));
@@ -520,8 +531,11 @@ int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
dstData[dstPos++] = value;
srcPos++;
} else {
- if (length > samplesLeft)
+ if (length > samplesLeft) {
length = samplesLeft;
+ if (ok != 0)
+ *ok = false;
+ }
if (_bigEndianSpeech) {
for (uint16 cnt = 0; cnt < (uint16)length; cnt++)
dstData[dstPos++] = (int16)SWAP_BYTES_16(*((uint16 *)(srcData + (srcPos++))));
@@ -535,6 +549,8 @@ int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
}
if (samplesLeft > 0) {
memset(dstData + dstPos, 0, samplesLeft * 2);
+ if (ok != 0)
+ *ok = false;
}
if (_cowMode == CowDemo) // demo has wave output size embedded in the compressed data
*(uint32 *)dstData = 0;
@@ -543,6 +559,8 @@ int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
calcWaveVolume(dstData, resSize);
return dstData;
} else {
+ if (ok != 0)
+ *ok = false;
free(fBuf);
warning("Sound::uncompressSpeech(): DATA tag not found in wave header");
*size = 0;
diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h
index e65e797934..18ee91dff2 100644
--- a/engines/sword1/sound.h
+++ b/engines/sword1/sound.h
@@ -110,7 +110,7 @@ private:
void initCowSystem();
uint32 getSampleId(int32 fxNo);
- int16 *uncompressSpeech(uint32 index, uint32 cSize, uint32 *size);
+ int16 *uncompressSpeech(uint32 index, uint32 cSize, uint32 *size, bool* ok = 0);
void calcWaveVolume(int16 *data, uint32 length);
bool _waveVolume[WAVE_VOL_TAB_LENGTH];
uint16 _waveVolPos;
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
index 1e9b7f70f4..1556f080e9 100644
--- a/engines/sword1/sword1.cpp
+++ b/engines/sword1/sword1.cpp
@@ -39,7 +39,6 @@
#include "engines/util.h"
#include "gui/message.h"
-#include "gui/gui-manager.h"
namespace Sword1 {
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
index eb24ef70fa..8dab522fd0 100644
--- a/engines/sword1/sword1.h
+++ b/engines/sword1/sword1.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SWORD1_H
-#define SWORD1_H
+#ifndef SWORD1_SWORD1_H
+#define SWORD1_SWORD1_H
#include "engines/engine.h"
#include "common/error.h"
@@ -150,4 +150,4 @@ private:
} // End of namespace Sword1
-#endif //BSSWORD1_H
+#endif // SWORD1_SWORD1_H
diff --git a/engines/sword2/configure.engine b/engines/sword2/configure.engine
index 7153605433..a794e7287c 100644
--- a/engines/sword2/configure.engine
+++ b/engines/sword2/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine sword2 "Broken Sword II" yes
+add_engine sword2 "Broken Sword II" yes "" "" "highres"
diff --git a/engines/sword2/music.cpp b/engines/sword2/music.cpp
index 62fb3d244d..462a49055d 100644
--- a/engines/sword2/music.cpp
+++ b/engines/sword2/music.cpp
@@ -35,10 +35,11 @@
#include "common/system.h"
#include "common/textconsole.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/vorbis.h"
#include "audio/decoders/flac.h"
-#include "audio/decoders/wave.h"
#include "audio/decoders/xa.h"
#include "audio/rate.h"
diff --git a/engines/sword2/screen.cpp b/engines/sword2/screen.cpp
index 0cb951fdfc..40baf67e46 100644
--- a/engines/sword2/screen.cpp
+++ b/engines/sword2/screen.cpp
@@ -1296,7 +1296,7 @@ void Screen::setPsxScrCache(byte *psxScrCache, uint8 level) {
}
byte *Screen::getPsxScrCache(uint8 level) {
- if (level > 3) {
+ if (level > 2) {
level = 0;
}
@@ -1307,7 +1307,7 @@ byte *Screen::getPsxScrCache(uint8 level) {
}
bool Screen::getPsxScrCacheStatus(uint8 level) {
- if (level > 3) {
+ if (level > 2) {
level = 0;
}
diff --git a/engines/sword2/sword2.h b/engines/sword2/sword2.h
index ef5c2b215e..65d1a955fb 100644
--- a/engines/sword2/sword2.h
+++ b/engines/sword2/sword2.h
@@ -22,8 +22,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef SWORD2_H
-#define SWORD2_H
+#ifndef SWORD2_SWORD2_H
+#define SWORD2_SWORD2_H
#define FRAMES_PER_SECOND 12
diff --git a/engines/sword25/POTFILES b/engines/sword25/POTFILES
new file mode 100644
index 0000000000..f4b0e6fc27
--- /dev/null
+++ b/engines/sword25/POTFILES
@@ -0,0 +1 @@
+engines/sword25/detection.cpp
diff --git a/engines/sword25/configure.engine b/engines/sword25/configure.engine
index 6a9428c758..f805483f54 100644
--- a/engines/sword25/configure.engine
+++ b/engines/sword25/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine sword25 "Broken Sword 2.5" yes "" "" "png zlib 16bit"
+add_engine sword25 "Broken Sword 2.5" yes "" "" "png zlib 16bit highres"
diff --git a/engines/sword25/detection.cpp b/engines/sword25/detection.cpp
index df68d11609..c5f55b5a26 100644
--- a/engines/sword25/detection.cpp
+++ b/engines/sword25/detection.cpp
@@ -21,6 +21,7 @@
*/
#include "base/plugins.h"
+#include "common/translation.h"
#include "engines/advancedDetector.h"
#include "sword25/sword25.h"
@@ -41,10 +42,17 @@ static const char *directoryGlobs[] = {
0
};
+static const ExtraGuiOption sword25ExtraGuiOption = {
+ _s("Use English speech"),
+ _s("Use English speech instead of German for every language other than German"),
+ "english_speech",
+ false
+};
+
class Sword25MetaEngine : public AdvancedMetaEngine {
public:
Sword25MetaEngine() : AdvancedMetaEngine(Sword25::gameDescriptions, sizeof(ADGameDescription), sword25Game) {
- _guioptions = GUIO1(GUIO_NOMIDI);
+ _guiOptions = GUIO1(GUIO_NOMIDI);
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
@@ -58,6 +66,7 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
virtual int getMaximumSaveSlot() const { return Sword25::PersistenceService::getSlotCount(); }
virtual SaveStateList listSaves(const char *target) const;
};
@@ -74,9 +83,15 @@ bool Sword25MetaEngine::hasFeature(MetaEngineFeature f) const {
(f == kSupportsListSaves);
}
+const ExtraGuiOptions Sword25MetaEngine::getExtraGuiOptions(const Common::String &target) const {
+ ExtraGuiOptions options;
+ options.push_back(sword25ExtraGuiOption);
+ return options;
+}
+
SaveStateList Sword25MetaEngine::listSaves(const char *target) const {
Common::String pattern = target;
- pattern = pattern + ".???";
+ pattern = pattern + ".###";
SaveStateList saveList;
Sword25::PersistenceService ps;
diff --git a/engines/sword25/detection_tables.h b/engines/sword25/detection_tables.h
index fa79bde4d5..927060bf18 100644
--- a/engines/sword25/detection_tables.h
+++ b/engines/sword25/detection_tables.h
@@ -132,11 +132,14 @@ static const ADGameDescription gameDescriptions[] = {
// Distributed by ScummVM
// Contains all language packs, English voice-overs and Hungarian version
+ // Mark it as Unknown Language since it contains multiple languages. If we
+ // mark it as English, then changing the language in-game causes the detection
+ // to fail the next time we try to start the engine.
{
"sword25",
"Latest version",
AD_ENTRY1s("data.b25c", "880a8a67faf4a4e7ab62cf114b771428", 827397764),
- Common::EN_ANY,
+ Common::UNK_LANG,
Common::kPlatformUnknown,
ADGF_NO_FLAGS,
GUIO1(GUIO_NOASPECT)
diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp
index eb0f0390dc..62a897a332 100644
--- a/engines/sword25/fmv/movieplayer.cpp
+++ b/engines/sword25/fmv/movieplayer.cpp
@@ -58,6 +58,8 @@ MoviePlayer::~MoviePlayer() {
}
bool MoviePlayer::loadMovie(const Common::String &filename, uint z) {
+ if (isMovieLoaded())
+ unloadMovie();
// Get the file and load it into the decoder
Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(filename);
_decoder.loadStream(in);
diff --git a/engines/sword25/gfx/animationresource.cpp b/engines/sword25/gfx/animationresource.cpp
index 431d466658..423a2b86b4 100644
--- a/engines/sword25/gfx/animationresource.cpp
+++ b/engines/sword25/gfx/animationresource.cpp
@@ -211,8 +211,9 @@ bool AnimationResource::precacheAllFrames() const {
error("Could not precache \"%s\".", (*iter).fileName.c_str());
return false;
}
-#else
- Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName);
+#else
+ Resource *pResource = Kernel::getInstance()->getResourceManager()->requestResource((*iter).fileName);
+ pResource->release(); //unlock precached resource
#endif
}
diff --git a/engines/sword25/gfx/fontresource.cpp b/engines/sword25/gfx/fontresource.cpp
index c4d4c3c52e..1d7aedcb6e 100644
--- a/engines/sword25/gfx/fontresource.cpp
+++ b/engines/sword25/gfx/fontresource.cpp
@@ -103,8 +103,9 @@ bool FontResource::parserCallback_font(ParserNode *node) {
if (!_pKernel->getResourceManager()->precacheResource(_bitmapFileName)) {
error("Could not precache \"%s\".", _bitmapFileName.c_str());
}
-#else
- _pKernel->getResourceManager()->requestResource(_bitmapFileName);
+#else
+ Resource *pResource = _pKernel->getResourceManager()->requestResource(_bitmapFileName);
+ pResource->release(); //unlock precached resource
#endif
return true;
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index a678fdccad..5d35a4f47e 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -217,6 +217,7 @@ Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement)
VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, const Common::String &fname) : _pixelData(0), _fname(fname) {
success = false;
+ _bgColor = 0;
// Create bitstream object
// In the following the file data will be readout of the bitstream object.
diff --git a/engines/sword25/gfx/renderobject.cpp b/engines/sword25/gfx/renderobject.cpp
index c109e49aa8..92d39c252d 100644
--- a/engines/sword25/gfx/renderobject.cpp
+++ b/engines/sword25/gfx/renderobject.cpp
@@ -71,19 +71,18 @@ RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type,
_version(++_nextGlobalVersion),
_isSolid(false) {
- // Renderobject registrieren, abhängig vom Handle-Parameter entweder mit beliebigem oder vorgegebenen Handle.
if (handle == 0)
_handle = RenderObjectRegistry::instance().registerObject(this);
else
_handle = RenderObjectRegistry::instance().registerObject(this, handle);
if (_handle == 0)
- return;
+ error("Failed to initialize RenderObject()");
updateAbsolutePos();
- // Dieses Objekt zu den Kindern der Elternobjektes hinzufügen, falls nicht Wurzel (ParentPtr ungültig) und dem
- // selben RenderObjektManager zuweisen.
+ // Add this item to the children of the parent object, if not root (ParentPtr is invalid),
+ // assign to the same RenderObjectManager.
if (_parentPtr.isValid()) {
_managerPtr = _parentPtr->getManager();
_parentPtr->addObject(this->getHandle());
@@ -100,24 +99,22 @@ RenderObject::RenderObject(RenderObjectPtr<RenderObject> parentPtr, TYPES type,
}
RenderObject::~RenderObject() {
- // Objekt aus dem Elternobjekt entfernen.
+ // Remove object from its parent.
if (_parentPtr.isValid())
_parentPtr->detatchChildren(this->getHandle());
deleteAllChildren();
- // Objekt deregistrieren.
RenderObjectRegistry::instance().deregisterObject(this);
}
void RenderObject::preRender(RenderObjectQueue *renderQueue) {
- // Objektänderungen validieren
validateObject();
if (!_visible)
return;
- // Falls notwendig, wird die Renderreihenfolge der Kinderobjekte aktualisiert.
+ // If necessary, update the children rendering order of the updated objects.
if (_childChanged) {
sortRenderObjects();
_childChanged = false;
@@ -149,7 +146,7 @@ bool RenderObject::render(RectangleList *updateRects, const Common::Array<int> &
if (needRender)
doRender(updateRects);
- // Dann müssen die Kinder gezeichnet werden
+ // Draw all children
RENDEROBJECT_ITER it = _children.begin();
for (; it != _children.end(); ++it)
if (!(*it)->render(updateRects, updateRectsMinZ))
@@ -159,7 +156,6 @@ bool RenderObject::render(RectangleList *updateRects, const Common::Array<int> &
}
void RenderObject::validateObject() {
- // Die Veränderungen in den Objektvariablen aufheben
_oldBbox = _bbox;
_oldVisible = _visible;
_oldX = _x;
@@ -169,15 +165,14 @@ void RenderObject::validateObject() {
}
bool RenderObject::updateObjectState() {
- // Falls sich das Objekt verändert hat, muss der interne Zustand neu berechnet werden und evtl. Update-Regions für den nächsten Frame
- // registriert werden.
+ // If the object has changed, the internal state must be recalculated and possibly
+ // update Regions be registered for the next frame.
if ((calcBoundingBox() != _oldBbox) ||
(_visible != _oldVisible) ||
(_x != _oldX) ||
(_y != _oldY) ||
(_z != _oldZ) ||
_refreshForced) {
- // Renderrang des Objektes neu bestimmen, da sich dieser verändert haben könnte
if (_parentPtr.isValid())
_parentPtr->signalChildChange();
@@ -200,12 +195,10 @@ bool RenderObject::updateObjectState() {
}
void RenderObject::updateBoxes() {
- // Bounding-Box aktualisieren
_bbox = calcBoundingBox();
}
Common::Rect RenderObject::calcBoundingBox() const {
- // Die Bounding-Box mit der Objektgröße initialisieren.
Common::Rect bbox(0, 0, _width, _height);
// Die absolute Position der Bounding-Box berechnen.
@@ -247,8 +240,6 @@ int32 RenderObject::calcAbsoluteZ() const {
}
void RenderObject::deleteAllChildren() {
- // Es ist nicht notwendig die Liste zu iterieren, da jedes Kind für sich DetatchChildren an diesem Objekt aufruft und sich somit
- // selber entfernt. Daher muss immer nur ein beliebiges Element (hier das letzte) gelöscht werden, bis die Liste leer ist.
while (!_children.empty()) {
RenderObjectPtr<RenderObject> curPtr = _children.back();
curPtr.erase();
@@ -261,10 +252,10 @@ bool RenderObject::addObject(RenderObjectPtr<RenderObject> pObject) {
return false;
}
- // Objekt in die Kinderliste einfügen.
+ // Insert Object in the children list.
_children.push_back(pObject);
- // Sicherstellen, dass vor dem nächsten Rendern die Renderreihenfolge aktualisiert wird.
+ // Make sure that before the next render the channel order is updated.
if (_parentPtr.isValid())
_parentPtr->signalChildChange();
diff --git a/engines/sword25/gfx/text.cpp b/engines/sword25/gfx/text.cpp
index d409c538c0..769c9b1162 100644
--- a/engines/sword25/gfx/text.cpp
+++ b/engines/sword25/gfx/text.cpp
@@ -77,7 +77,8 @@ bool Text::setFont(const Common::String &font) {
return false;
}
#else
- getResourceManager()->requestResource(font);
+ Resource *pResource = getResourceManager()->requestResource(font);
+ pResource->release(); //unlock precached resource
_font = font;
updateFormat();
forceRefresh();
diff --git a/engines/sword25/package/packagemanager.cpp b/engines/sword25/package/packagemanager.cpp
index 2db4f2da74..87bedcc9c1 100644
--- a/engines/sword25/package/packagemanager.cpp
+++ b/engines/sword25/package/packagemanager.cpp
@@ -56,7 +56,8 @@ static Common::String normalizePath(const Common::String &path, const Common::St
PackageManager::PackageManager(Kernel *pKernel) : Service(pKernel),
_currentDirectory(PATH_SEPARATOR),
- _rootFolder(ConfMan.get("path")) {
+ _rootFolder(ConfMan.get("path")),
+ _useEnglishSpeech(ConfMan.getBool("english_speech")) {
if (!registerScriptBindings())
error("Script bindings could not be registered.");
else
@@ -71,14 +72,34 @@ PackageManager::~PackageManager() {
}
+Common::String PackageManager::ensureSpeechLang(const Common::String &fileName) {
+ if (!_useEnglishSpeech || fileName.size() < 9 || !fileName.hasPrefix("/speech/"))
+ return fileName;
+
+ // Always keep German speech as a fallback in case the English speech pack is not present.
+ // However this means we cannot play with German text and English voice.
+ if (fileName.hasPrefix("/speech/de"))
+ return fileName;
+
+ Common::String newFileName = "/speech/en";
+ uint fileIdx = 9;
+ while (fileIdx < fileName.size() && fileName[fileIdx] != '/')
+ ++fileIdx;
+ if (fileIdx < fileName.size())
+ newFileName += fileName.c_str() + fileIdx;
+
+ return newFileName;
+}
+
/**
* Scans through the archive list for a specified file
*/
Common::ArchiveMemberPtr PackageManager::getArchiveMember(const Common::String &fileName) {
+ Common::String fileName2 = ensureSpeechLang(fileName);
// Loop through checking each archive
Common::List<ArchiveEntry *>::iterator i;
for (i = _archiveList.begin(); i != _archiveList.end(); ++i) {
- if (!fileName.hasPrefix((*i)->_mountPath)) {
+ if (!fileName2.hasPrefix((*i)->_mountPath)) {
// The mount path is in different subtree. Skipping
continue;
}
@@ -87,7 +108,7 @@ Common::ArchiveMemberPtr PackageManager::getArchiveMember(const Common::String &
Common::Archive *archiveFolder = (*i)->archive;
// Construct relative path
- Common::String resPath(&fileName.c_str()[(*i)->_mountPath.size()]);
+ Common::String resPath(&fileName2.c_str()[(*i)->_mountPath.size()]);
if (archiveFolder->hasFile(resPath)) {
return archiveFolder->getMember(resPath);
@@ -203,23 +224,29 @@ bool PackageManager::changeDirectory(const Common::String &directory) {
}
Common::String PackageManager::getAbsolutePath(const Common::String &fileName) {
- return normalizePath(fileName, _currentDirectory);
+ return normalizePath(ensureSpeechLang(fileName), _currentDirectory);
}
bool PackageManager::fileExists(const Common::String &fileName) {
// FIXME: The current Zip implementation doesn't support getting a folder entry, which is needed for detecting
- // the English voick pack
- if (fileName == "/speech/en") {
+ // the English voice pack
+ Common::String fileName2 = ensureSpeechLang(fileName);
+ if (fileName2 == "/speech/en") {
// To get around this, change to detecting one of the files in the folder
- return getArchiveMember(normalizePath(fileName + "/APO0001.ogg", _currentDirectory));
+ bool exists = getArchiveMember(normalizePath(fileName2 + "/APO0001.ogg", _currentDirectory));
+ if (!exists && _useEnglishSpeech) {
+ _useEnglishSpeech = false;
+ warning("English speech not found");
+ }
+ return exists;
}
- Common::ArchiveMemberPtr fileNode = getArchiveMember(normalizePath(fileName, _currentDirectory));
+ Common::ArchiveMemberPtr fileNode = getArchiveMember(normalizePath(fileName2, _currentDirectory));
return fileNode;
}
int PackageManager::doSearch(Common::ArchiveMemberList &list, const Common::String &filter, const Common::String &path, uint typeFilter) {
- Common::String normalizedFilter = normalizePath(filter, _currentDirectory);
+ Common::String normalizedFilter = normalizePath(ensureSpeechLang(filter), _currentDirectory);
int num = 0;
if (path.size() > 0)
diff --git a/engines/sword25/package/packagemanager.h b/engines/sword25/package/packagemanager.h
index a1806a4046..5475cb02fc 100644
--- a/engines/sword25/package/packagemanager.h
+++ b/engines/sword25/package/packagemanager.h
@@ -87,6 +87,9 @@ private:
Common::String _currentDirectory;
Common::FSNode _rootFolder;
Common::List<ArchiveEntry *> _archiveList;
+
+ bool _useEnglishSpeech;
+ Common::String ensureSpeechLang(const Common::String &fileName);
Common::ArchiveMemberPtr getArchiveMember(const Common::String &fileName);
diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp
index dcb29cb380..46f27b06f0 100644
--- a/engines/sword25/sfx/soundengine.cpp
+++ b/engines/sword25/sfx/soundengine.cpp
@@ -36,6 +36,7 @@
#include "sword25/kernel/inputpersistenceblock.h"
#include "sword25/kernel/outputpersistenceblock.h"
+#include "audio/audiostream.h"
#include "audio/decoders/vorbis.h"
#include "common/system.h"
diff --git a/engines/sword25/sfx/soundengine.h b/engines/sword25/sfx/soundengine.h
index 1dd7ba0925..9bf251be15 100644
--- a/engines/sword25/sfx/soundengine.h
+++ b/engines/sword25/sfx/soundengine.h
@@ -49,7 +49,6 @@
#include "sword25/kernel/resservice.h"
#include "sword25/kernel/persistable.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
namespace Sword25 {
diff --git a/engines/sword25/sword25.h b/engines/sword25/sword25.h
index 72391cf9d8..c08f20e3b3 100644
--- a/engines/sword25/sword25.h
+++ b/engines/sword25/sword25.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef SWORD25_H
-#define SWORD25_H
+#ifndef SWORD25_SWORD25_H
+#define SWORD25_SWORD25_H
#include "common/scummsys.h"
#include "engines/engine.h"
diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp
index cefc1a89d3..caa7bdbec9 100644
--- a/engines/teenagent/detection.cpp
+++ b/engines/teenagent/detection.cpp
@@ -88,7 +88,7 @@ enum {
class TeenAgentMetaEngine : public AdvancedMetaEngine {
public:
TeenAgentMetaEngine() : AdvancedMetaEngine(teenAgentGameDescriptions, sizeof(ADGameDescription), teenAgentGames) {
- _singleid = "teenagent";
+ _singleId = "teenagent";
}
virtual const char *getName() const {
diff --git a/engines/teenagent/font.cpp b/engines/teenagent/font.cpp
index ab75a45ba7..f691ace32d 100644
--- a/engines/teenagent/font.cpp
+++ b/engines/teenagent/font.cpp
@@ -25,6 +25,7 @@
#include "teenagent/pack.h"
#include "teenagent/teenagent.h"
+#include "common/debug.h"
#include "common/endian.h"
#include "common/stream.h"
#include "common/textconsole.h"
diff --git a/engines/teenagent/music.cpp b/engines/teenagent/music.cpp
index 5d66c3c90c..795b8f7312 100644
--- a/engines/teenagent/music.cpp
+++ b/engines/teenagent/music.cpp
@@ -36,7 +36,7 @@ static const uint32 noteToPeriod[3][12] = {
{214, 201, 189, 179, 170, 160, 151, 143, 135, 127, 120, 113}
};
-MusicPlayer::MusicPlayer(TeenAgentEngine *vm) : Paula(false, 44100, 5000), _vm(vm), _id(0) {
+MusicPlayer::MusicPlayer(TeenAgentEngine *vm) : Paula(false, 44100, 5000), _vm(vm), _id(0), _currRow(0) {
}
MusicPlayer::~MusicPlayer() {
@@ -55,7 +55,7 @@ bool MusicPlayer::load(int id) {
Common::StackLock lock(_mutex);
// Load the samples
- sampleCount = stream->readByte();
+ byte sampleCount = stream->readByte();
debugC(0, kDebugMusic, "sampleCount = %d", sampleCount);
diff --git a/engines/teenagent/music.h b/engines/teenagent/music.h
index e1630cc845..4b1b683a30 100644
--- a/engines/teenagent/music.h
+++ b/engines/teenagent/music.h
@@ -74,7 +74,6 @@ private:
size = 0;
}
} _samples[256];
- byte sampleCount;
Common::Array<Row> _rows;
uint _currRow;
diff --git a/engines/teenagent/objects.h b/engines/teenagent/objects.h
index f923ae52ab..1f8a82a66e 100644
--- a/engines/teenagent/objects.h
+++ b/engines/teenagent/objects.h
@@ -165,7 +165,7 @@ struct Object {
//19
Common::String name, description;
- Object(): _base(NULL) {}
+ Object(): _base(NULL) { id = 0; actorOrientation = 0; enabled = 0; }
void dump(int level = 0) const;
void setName(const Common::String &newName);
void load(byte *addr);
@@ -205,7 +205,7 @@ struct Walkbox {
Rect rect;
byte sideHint[4];
- Walkbox() : _base(NULL) {}
+ Walkbox() : _base(NULL) { memset(this, 0, sizeof(Walkbox)); }
void dump(int level = 0) const;
void load(byte *src);
void save() const;
diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp
index 8d8f705a24..3cf566a0e5 100644
--- a/engines/teenagent/resources.cpp
+++ b/engines/teenagent/resources.cpp
@@ -22,6 +22,7 @@
#include "teenagent/resources.h"
#include "teenagent/teenagent.h"
+#include "common/debug.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "common/zlib.h"
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
index 6e1cef31bc..c250269844 100644
--- a/engines/teenagent/scene.cpp
+++ b/engines/teenagent/scene.cpp
@@ -71,6 +71,9 @@ Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0),
varia.close();
loadObjectData();
+
+ _onsCount = 0;
+ _messageColor = 0;
}
Scene::~Scene() {
@@ -314,7 +317,7 @@ void Scene::loadOns() {
uint16 addr = _vm->res->dseg.get_word(dsAddr_onsAnimationTablePtr + (_id - 1) * 2);
debugC(0, kDebugScene, "ons index: %04x", addr);
- onsCount = 0;
+ _onsCount = 0;
byte b;
byte onId[16];
while ((b = _vm->res->dseg.get_byte(addr)) != 0xff) {
@@ -323,15 +326,15 @@ void Scene::loadOns() {
if (b == 0)
continue;
- onId[onsCount++] = b;
+ onId[_onsCount++] = b;
}
delete[] ons;
ons = NULL;
- if (onsCount > 0) {
- ons = new Surface[onsCount];
- for (uint32 i = 0; i < onsCount; ++i) {
+ if (_onsCount > 0) {
+ ons = new Surface[_onsCount];
+ for (uint32 i = 0; i < _onsCount; ++i) {
Common::ScopedPtr<Common::SeekableReadStream> s(_vm->res->ons.getStream(onId[i]));
if (s) {
ons[i].load(*s, Surface::kTypeOns);
@@ -498,7 +501,7 @@ bool Scene::processEvent(const Common::Event &event) {
events.clear();
sounds.clear();
currentEvent.clear();
- messageColor = textColorMark;
+ _messageColor = textColorMark;
for (int i = 0; i < 4; ++i)
customAnimation[i].free();
_vm->playMusic(4);
@@ -651,7 +654,7 @@ bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) {
bool gotAnyAnimation = false;
if (ons != NULL && debugFeatures.feature[DebugFeatures::kShowOns]) {
- for (uint32 i = 0; i < onsCount; ++i) {
+ for (uint32 i = 0; i < _onsCount; ++i) {
Surface *s = ons + i;
if (s != NULL)
s->render(surface);
@@ -821,7 +824,7 @@ bool Scene::render(bool tickGame, bool tickMark, uint32 messageDelta) {
}
if (visible) {
- _vm->res->font7.render(surface, messagePos.x, messagePos.y, message, messageColor);
+ _vm->res->font7.render(surface, messagePos.x, messagePos.y, message, _messageColor);
busy = true;
}
}
@@ -1005,7 +1008,7 @@ bool Scene::processEventQueue() {
warning("no animation in slot %u", messageSlot);
}
messagePos = messagePosition(message, p);
- messageColor = currentEvent.color;
+ _messageColor = currentEvent.color;
if (messageFirstFrame)
currentEvent.clear(); // async message, clearing event
@@ -1153,7 +1156,7 @@ bool Scene::processEventQueue() {
}
if (events.empty()) {
- messageColor = textColorMark;
+ _messageColor = textColorMark;
hideActor = false;
}
@@ -1232,7 +1235,7 @@ void Scene::displayMessage(const Common::String &str, byte color, const Common::
debugC(0, kDebugScene, "displayMessage: %s", str.c_str());
message = str;
messagePos = (pos.x | pos.y) ? pos : messagePosition(str, position);
- messageColor = color;
+ _messageColor = color;
messageTimer = messageDuration(message);
}
@@ -1251,7 +1254,7 @@ void Scene::clear() {
void Scene::clearMessage() {
message.clear();
messageTimer = 0;
- messageColor = textColorMark;
+ _messageColor = textColorMark;
messageFirstFrame = 0;
messageLastFrame = 0;
messageAnimation = NULL;
diff --git a/engines/teenagent/scene.h b/engines/teenagent/scene.h
index 07b304ed97..40f910a3aa 100644
--- a/engines/teenagent/scene.h
+++ b/engines/teenagent/scene.h
@@ -194,7 +194,7 @@ private:
SurfaceList on;
bool onEnabled;
Surface *ons;
- uint32 onsCount;
+ uint32 _onsCount;
Animation actorAnimation, animation[4], customAnimation[4];
Common::Rect actorAnimationPosition, animationPosition[4];
@@ -214,7 +214,7 @@ private:
Common::String message;
Common::Point messagePos;
- byte messageColor;
+ byte _messageColor;
uint messageTimer;
byte messageFirstFrame;
byte messageLastFrame;
diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp
index d5a8b8e2dc..2d10b82f51 100644
--- a/engines/teenagent/teenagent.cpp
+++ b/engines/teenagent/teenagent.cpp
@@ -71,6 +71,13 @@ TeenAgentEngine::TeenAgentEngine(OSystem *system, const ADGameDescription *gd)
res = new Resources();
console = 0;
+ scene = 0;
+ inventory = 0;
+ _sceneBusy = false;
+ _dstObject = 0;
+ _musicStream = 0;
+ _markDelay = 0;
+ _gameDelay = 0;
}
TeenAgentEngine::~TeenAgentEngine() {
@@ -545,6 +552,10 @@ Common::Error TeenAgentEngine::run() {
syncSoundSettings();
+ // Initialize CD audio
+ if (_gameDescription->flags & ADGF_CD)
+ g_system->getAudioCDManager()->open();
+
setMusic(1);
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, music, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false);
diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h
index a06f8dbf9b..438f06d189 100644
--- a/engines/teenagent/teenagent.h
+++ b/engines/teenagent/teenagent.h
@@ -20,16 +20,14 @@
*
*/
-#ifndef TEENAGENT_ENGINE_H
-#define TEENAGENT_ENGINE_H
+#ifndef TEENAGENT_TEENAGENT_H
+#define TEENAGENT_TEENAGENT_H
#include "engines/engine.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/random.h"
-#include "common/rect.h"
#include "common/array.h"
#include "gui/debugger.h"
@@ -39,6 +37,14 @@
struct ADGameDescription;
+namespace Audio {
+class AudioStream;
+}
+
+namespace Common {
+struct Point;
+}
+
/**
* This is the namespace of the TeenAgent engine.
*
@@ -53,7 +59,6 @@ struct Object;
struct UseHotspot;
class Scene;
class MusicPlayer;
-class Dialog;
class Resources;
class Inventory;
diff --git a/engines/testbed/config.h b/engines/testbed/config.h
index db687de261..738f07ab87 100644
--- a/engines/testbed/config.h
+++ b/engines/testbed/config.h
@@ -30,7 +30,7 @@
#include "common/tokenizer.h"
#include "gui/widgets/list.h"
-#include "gui/options.h"
+#include "gui/dialog.h"
#include "gui/ThemeEngine.h"
#include "testbed/testsuite.h"
diff --git a/engines/testbed/detection.cpp b/engines/testbed/detection.cpp
index 348ade62b0..7aff7a1805 100644
--- a/engines/testbed/detection.cpp
+++ b/engines/testbed/detection.cpp
@@ -49,7 +49,7 @@ class TestbedMetaEngine : public AdvancedMetaEngine {
public:
TestbedMetaEngine() : AdvancedMetaEngine(testbedDescriptions, sizeof(ADGameDescription), testbed_setting) {
_md5Bytes = 512;
- _singleid = "testbed";
+ _singleId = "testbed";
}
virtual const char *getName() const {
diff --git a/engines/testbed/midi.cpp b/engines/testbed/midi.cpp
index daa5f1cf3c..5ede21f4ab 100644
--- a/engines/testbed/midi.cpp
+++ b/engines/testbed/midi.cpp
@@ -27,6 +27,7 @@
#include "graphics/cursorman.h"
#include "audio/mididrv.h"
+#include "audio/midiparser.h"
#include "testbed/midi.h"
#include "testbed/testbed.h"
diff --git a/engines/testbed/midi.h b/engines/testbed/midi.h
index b9f3e82abd..5ed0a73913 100644
--- a/engines/testbed/midi.h
+++ b/engines/testbed/midi.h
@@ -23,12 +23,16 @@
#ifndef TESTBED_MIDI_H
#define TESTBED_MIDI_H
-#include "common/stream.h"
-#include "audio/midiparser.h"
#include "testbed/testsuite.h"
// This file can be used as template for header files of other newer testsuites.
+class MidiParser;
+
+namespace Common {
+class WriteStream;
+}
+
namespace Testbed {
namespace MidiTests {
diff --git a/engines/testbed/sound.h b/engines/testbed/sound.h
index 893a89b175..5de8877284 100644
--- a/engines/testbed/sound.h
+++ b/engines/testbed/sound.h
@@ -23,7 +23,6 @@
#ifndef TESTBED_SOUND_H
#define TESTBED_SOUND_H
-#include "gui/dialog.h"
#include "audio/mixer.h"
#include "testbed/config.h"
#include "testbed/testsuite.h"
diff --git a/engines/testbed/testbed.h b/engines/testbed/testbed.h
index 0f70e1191f..5ea05feba2 100644
--- a/engines/testbed/testbed.h
+++ b/engines/testbed/testbed.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TESTBED_H
-#define TESTBED_H
+#ifndef TESTBED_TESTBED_H
+#define TESTBED_TESTBED_H
#include "common/array.h"
@@ -72,4 +72,4 @@ private:
} // End of namespace Testbed
-#endif // TESTBED_H
+#endif // TESTBED_TESTBED_H
diff --git a/engines/tinsel/bmv.cpp b/engines/tinsel/bmv.cpp
index f28cd684f9..cfe97e6ec1 100644
--- a/engines/tinsel/bmv.cpp
+++ b/engines/tinsel/bmv.cpp
@@ -39,6 +39,7 @@
#include "tinsel/tinlib.h"
#include "tinsel/tinsel.h"
+#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "common/textconsole.h"
@@ -566,8 +567,8 @@ void BMVPlayer::PlayBMV(CORO_PARAM, SCNHANDLE hFileStem, int myEscape) {
assert(!bMovieOn);
- strcpy(szMovieFile, (char *)LockMem(hFileStem));
- strcat(szMovieFile, BMOVIE_EXTENSION);
+ Common::strlcpy(szMovieFile, (char *)LockMem(hFileStem), 14);
+ Common::strlcat(szMovieFile, BMOVIE_EXTENSION, 14);
assert(strlen(szMovieFile) <= 12);
diff --git a/engines/tinsel/bmv.h b/engines/tinsel/bmv.h
index e52297f9de..888f910627 100644
--- a/engines/tinsel/bmv.h
+++ b/engines/tinsel/bmv.h
@@ -27,12 +27,15 @@
#include "common/coroutines.h"
#include "common/file.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "tinsel/object.h"
#include "tinsel/palette.h"
+namespace Audio {
+class QueuingAudioStream;
+}
+
namespace Tinsel {
diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp
index 0c7d0b0665..c44f1f4ef3 100644
--- a/engines/tinsel/detection.cpp
+++ b/engines/tinsel/detection.cpp
@@ -85,7 +85,7 @@ static const PlainGameDescriptor tinselGames[] = {
class TinselMetaEngine : public AdvancedMetaEngine {
public:
TinselMetaEngine() : AdvancedMetaEngine(Tinsel::gameDescriptions, sizeof(Tinsel::TinselGameDescription), tinselGames) {
- _singleid = "tinsel";
+ _singleId = "tinsel";
}
virtual const char *getName() const {
@@ -228,14 +228,14 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
// Check which files are included in some dw2 ADGameDescription *and* present
// in fslist without a '1' suffix character. Compute MD5s and file sizes for these files.
- for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) {
- if (strcmp(g->desc.gameid, "dw2") != 0)
+ for (g = &Tinsel::gameDescriptions[0]; g->desc.gameId != 0; ++g) {
+ if (strcmp(g->desc.gameId, "dw2") != 0)
continue;
for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
// Get the next filename, stripping off any '1' suffix character
char tempFilename[50];
- strcpy(tempFilename, fileDesc->fileName);
+ Common::strlcpy(tempFilename, fileDesc->fileName, 50);
char *pOne = strchr(tempFilename, '1');
if (pOne) {
do {
@@ -265,8 +265,8 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
int maxFilesMatched = 0;
// MD5 based matching
- for (g = &Tinsel::gameDescriptions[0]; g->desc.gameid != 0; ++g) {
- if (strcmp(g->desc.gameid, "dw2") != 0)
+ for (g = &Tinsel::gameDescriptions[0]; g->desc.gameId != 0; ++g) {
+ if (strcmp(g->desc.gameId, "dw2") != 0)
continue;
bool fileMissing = false;
@@ -275,7 +275,7 @@ const ADGameDescription *TinselMetaEngine::fallbackDetect(const FileMap &allFile
for (fileDesc = g->desc.filesDescriptions; fileDesc->fileName; fileDesc++) {
// Get the next filename, stripping off any '1' suffix character
char tempFilename[50];
- strcpy(tempFilename, fileDesc->fileName);
+ Common::strlcpy(tempFilename, fileDesc->fileName, 50);
char *pOne = strchr(tempFilename, '1');
if (pOne) {
do {
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index a84dad942c..b5d090ec15 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -1671,10 +1671,10 @@ static void Select(int i, bool force) {
#else
// Current description with cursor appended
if (cd.box[i].boxText != NULL) {
- strcpy(g_sedit, cd.box[i].boxText);
- strcat(g_sedit, sCursor);
+ Common::strlcpy(g_sedit, cd.box[i].boxText, SG_DESC_LEN+2);
+ Common::strlcat(g_sedit, sCursor, SG_DESC_LEN+2);
} else {
- strcpy(g_sedit, sCursor);
+ Common::strlcpy(g_sedit, sCursor, SG_DESC_LEN+2);
}
#endif
@@ -3676,13 +3676,13 @@ extern void HideConversation(bool bHide) {
ConstructInventory(FULL);
else {
// Move it all back on-screen
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiAdjustXY(g_objArray[i], -2 * SCREEN_WIDTH, 0);
}
// Don't flash if items changed. If they have, will be redrawn anyway.
if (TinselV2 || !g_ItemsChanged) {
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiAdjustXY(g_iconArray[i], -2*SCREEN_WIDTH, 0);
}
}
@@ -3739,10 +3739,10 @@ extern void HideConversation(bool bHide) {
deltay = g_InvD[INV_CONV].inventoryY - deltay;
// Move it all
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiMoveRelXY(g_objArray[i], x - center, deltay);
}
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiMoveRelXY(g_iconArray[i], x - center, deltay);
}
g_InvD[INV_CONV].inventoryX += x - center;
@@ -3771,10 +3771,10 @@ extern void HideConversation(bool bHide) {
y = 0;
if (x || y) {
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiMoveRelXY(g_objArray[i], x, y);
}
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiMoveRelXY(g_iconArray[i], x, y);
}
g_InvD[INV_CONV].inventoryX += x;
@@ -3786,10 +3786,10 @@ extern void HideConversation(bool bHide) {
*/
if (MultiLowest(g_RectObject) > SCREEN_BOX_HEIGHT2 - SysVar(SV_CONV_MINY)) {
y = (SCREEN_BOX_HEIGHT2 - SysVar(SV_CONV_MINY)) - MultiLowest(g_RectObject);
- for (i = 0; g_objArray[i] && i < MAX_WCOMP; i++) {
+ for (i = 0; i < MAX_WCOMP && g_objArray[i]; i++) {
MultiMoveRelXY(g_objArray[i], 0, y);
}
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++) {
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++) {
MultiMoveRelXY(g_iconArray[i], 0, y);
}
g_InvD[INV_CONV].inventoryY += y;
@@ -4617,9 +4617,9 @@ extern void Xmovement(int x) {
GetAniPosition(g_objArray[0], &g_InvD[g_ino].inventoryX, &aniY);
g_InvD[g_ino].inventoryX +=x;
MultiSetAniX(g_objArray[0], g_InvD[g_ino].inventoryX);
- for (i = 1; g_objArray[i] && i < MAX_WCOMP; i++)
+ for (i = 1; i < MAX_WCOMP && g_objArray[i]; i++)
MultiMoveRelXY(g_objArray[i], x, 0);
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++)
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++)
MultiMoveRelXY(g_iconArray[i], x, 0);
break;
@@ -4665,9 +4665,9 @@ extern void Ymovement(int y) {
GetAniPosition(g_objArray[0], &aniX, &g_InvD[g_ino].inventoryY);
g_InvD[g_ino].inventoryY +=y;
MultiSetAniY(g_objArray[0], g_InvD[g_ino].inventoryY);
- for (i = 1; g_objArray[i] && i < MAX_WCOMP; i++)
+ for (i = 1; i < MAX_WCOMP && g_objArray[i]; i++)
MultiMoveRelXY(g_objArray[i], 0, y);
- for (i = 0; g_iconArray[i] && i < MAX_ICONS; i++)
+ for (i = 0; i < MAX_ICONS && g_iconArray[i]; i++)
MultiMoveRelXY(g_iconArray[i], 0, y);
break;
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 62d244e449..9ffd477c4a 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -258,7 +258,7 @@ void LoadExtraGraphData(SCNHANDLE start, SCNHANDLE next) {
}
void SetCdPlaySceneDetails(int fileNum, const char *fileName) {
- strcpy(g_szCdPlayFile, fileName);
+ Common::strlcpy(g_szCdPlayFile, fileName, 100);
}
void SetCdPlayHandle(int fileNum) {
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index e0c1f8d1f9..dc7ca67cfe 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -29,7 +29,6 @@
#include "audio/midiparser.h"
// Miles Audio for Discworld 1
#include "audio/miles.h"
-#include "audio/decoders/adpcm.h"
#include "backends/audiocd/audiocd.h"
@@ -402,7 +401,7 @@ MidiMusicPlayer::MidiMusicPlayer(TinselEngine *vm) {
if (milesAudioEnabled) {
// Discworld 1 (DOS) uses Miles Audio 3
// use our own Miles Audio drivers
- //
+ //
// It seems that there are multiple versions of Discworld 1
//
// Version 1:
@@ -640,10 +639,14 @@ PCMMusicPlayer::PCMMusicPlayer() {
_dimmed = false;
_dimmedTinsel = false;
_dimIteration = 0;
+ _dimmedVolume = 0;
+ _dimPosition = 0;
_fadeOutVolume = 0;
_fadeOutIteration = 0;
+ _hScript = _hSegment = 0;
+
_end = true;
_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType,
diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp
index 918894cf6f..495049d1a2 100644
--- a/engines/tinsel/palette.cpp
+++ b/engines/tinsel/palette.cpp
@@ -132,6 +132,8 @@ void PalettesToVideoDAC() {
VIDEO_DAC_Q *pDACtail = g_vidDACdata; // set tail pointer
byte pal[768];
+ memset(pal, 0, sizeof(pal));
+
// while Q is not empty
while (g_pDAChead != pDACtail) {
const PALETTE *pPalette; // pointer to hardware palette
diff --git a/engines/tinsel/play.cpp b/engines/tinsel/play.cpp
index ef3127233d..a4f5bc8261 100644
--- a/engines/tinsel/play.cpp
+++ b/engines/tinsel/play.cpp
@@ -159,6 +159,9 @@ static int RegisterSoundReel(SCNHANDLE hFilm, int column, int actorCol) {
}
}
+ if (i == MAX_SOUNDREELS)
+ error("Out of sound reels in RegisterSoundReel()");
+
g_soundReelNumbers[i]++;
return i;
}
diff --git a/engines/tinsel/saveload.cpp b/engines/tinsel/saveload.cpp
index 88cd80b78a..c8fe5f898c 100644
--- a/engines/tinsel/saveload.cpp
+++ b/engines/tinsel/saveload.cpp
@@ -563,7 +563,7 @@ static void DoSave() {
while (1) {
Common::String fname = _vm->getSavegameFilename(ano);
- strcpy(tmpName, fname.c_str());
+ Common::strlcpy(tmpName, fname.c_str(), FNAMELEN);
for (i = 0; i < g_numSfiles; i++)
if (!strcmp(g_savedFiles[i].name, tmpName))
@@ -594,8 +594,8 @@ static void DoSave() {
hdr.id = SAVEGAME_ID;
hdr.size = SAVEGAME_HEADER_SIZE;
hdr.ver = CURRENT_VER;
- memcpy(hdr.desc, g_SaveSceneDesc, SG_DESC_LEN);
- hdr.desc[SG_DESC_LEN - 1] = 0;
+ memset(hdr.desc, 0, SG_DESC_LEN);
+ Common::strlcpy(hdr.desc, g_SaveSceneDesc, SG_DESC_LEN);
g_system->getTimeAndDate(hdr.dateTime);
hdr.scnFlag = _vm->getFeatures() & GF_SCNFILES;
hdr.language = _vm->_config->_language;
diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp
index 3d87a17331..a13e91fb3c 100644
--- a/engines/tinsel/sound.cpp
+++ b/engines/tinsel/sound.cpp
@@ -27,7 +27,6 @@
#include "tinsel/dw.h"
#include "tinsel/config.h"
#include "tinsel/music.h"
-#include "tinsel/strres.h"
#include "tinsel/tinsel.h"
#include "tinsel/sysvar.h"
#include "tinsel/background.h"
@@ -37,7 +36,6 @@
#include "common/system.h"
#include "audio/mixer.h"
-#include "audio/decoders/adpcm.h"
#include "audio/decoders/flac.h"
#include "audio/decoders/mp3.h"
#include "audio/decoders/raw.h"
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 2adddca4fd..44e81494f7 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -823,6 +823,9 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
_console(0), _sound(0), _midiMusic(0), _pcmMusic(0), _bmv(0) {
_vm = this;
+ _gameId = 0;
+ _driver = NULL;
+
_config = new Config(this);
// Register debug flags
@@ -841,9 +844,7 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
if (!scumm_stricmp(g->gameid, gameid))
_gameId = g->id;
- int cd_num = ConfMan.getInt("cdrom");
- if (cd_num >= 0)
- _system->getAudioCDManager()->openCD(cd_num);
+ _system->getAudioCDManager()->open();
_mousePos.x = 0;
_mousePos.y = 0;
@@ -975,7 +976,7 @@ Common::Error TinselEngine::run() {
// Check for time to do next game cycle
if ((g_system->getMillis() > timerVal + GAME_FRAME_DELAY)) {
timerVal = g_system->getMillis();
- _system->getAudioCDManager()->updateCD();
+ _system->getAudioCDManager()->update();
NextGameCycle();
}
diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h
index c83bc80ead..9e4ce61b04 100644
--- a/engines/tinsel/tinsel.h
+++ b/engines/tinsel/tinsel.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TINSEL_H
-#define TINSEL_H
+#ifndef TINSEL_TINSEL_H
+#define TINSEL_TINSEL_H
#include "common/scummsys.h"
#include "common/system.h"
@@ -251,4 +251,4 @@ void CdHasChanged();
} // End of namespace Tinsel
-#endif /* TINSEL_H */
+#endif /* TINSEL_TINSEL_H */
diff --git a/engines/toltecs/animation.cpp b/engines/toltecs/animation.cpp
index 1f776bbc02..5278b25ba8 100644
--- a/engines/toltecs/animation.cpp
+++ b/engines/toltecs/animation.cpp
@@ -29,6 +29,18 @@ namespace Toltecs {
AnimationPlayer::AnimationPlayer(ToltecsEngine *vm) : _vm(vm) {
_animBuffer = new byte[262144];
+ memset(_animBuffer, 0, 262144);
+
+ _resIndex = 0;
+ _width = _height = 0;
+ _frameNumber = 0;
+ _frameCount = 0;
+ _keepFrameCounter = 0;
+ _curFrameSize = _nextFrameSize = 0;
+ _nextFrameOffset = 0;
+ _firstNextFrameSize = 0;
+ _firstNextFrameOffset = 0;
+ _firstCurFrameSize = 0;
}
AnimationPlayer::~AnimationPlayer() {
diff --git a/engines/toltecs/configure.engine b/engines/toltecs/configure.engine
index be5533efa2..8310a6d6ef 100644
--- a/engines/toltecs/configure.engine
+++ b/engines/toltecs/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine toltecs "3 Skulls of the Toltecs" yes
+add_engine toltecs "3 Skulls of the Toltecs" yes "" "" "highres"
diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp
index 145d9544f2..7c707895e6 100644
--- a/engines/toltecs/detection.cpp
+++ b/engines/toltecs/detection.cpp
@@ -206,7 +206,7 @@ static const ExtraGuiOption toltecsExtraGuiOption = {
class ToltecsMetaEngine : public AdvancedMetaEngine {
public:
ToltecsMetaEngine() : AdvancedMetaEngine(Toltecs::gameDescriptions, sizeof(Toltecs::ToltecsGameDescription), toltecsGames) {
- _singleid = "toltecs";
+ _singleId = "toltecs";
}
virtual const char *getName() const {
diff --git a/engines/toltecs/menu.cpp b/engines/toltecs/menu.cpp
index a58771433e..5fc0599c2a 100644
--- a/engines/toltecs/menu.cpp
+++ b/engines/toltecs/menu.cpp
@@ -37,6 +37,16 @@
namespace Toltecs {
MenuSystem::MenuSystem(ToltecsEngine *vm) : _vm(vm) {
+ _background = nullptr;
+ _running = false;
+ _currMenuID = _newMenuID = kMenuIdNone;
+ _currItemID = kItemIdNone;
+ _top = 0;
+ _savegameListTopIndex = 0;
+ _editingDescription = false;
+ _editingDescriptionID = kItemIdNone;
+ _editingDescriptionItem = nullptr;
+ _needRedraw = false;
}
MenuSystem::~MenuSystem() {
diff --git a/engines/toltecs/movie.cpp b/engines/toltecs/movie.cpp
index 0aa0a99a36..b26408fadc 100644
--- a/engines/toltecs/movie.cpp
+++ b/engines/toltecs/movie.cpp
@@ -20,6 +20,7 @@
*
*/
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
@@ -44,7 +45,7 @@ enum ChunkTypes {
kChunkStopSubtitles = 8
};
-MoviePlayer::MoviePlayer(ToltecsEngine *vm) : _vm(vm), _isPlaying(false), _lastPrefetchOfs(0), _framesPerSoundChunk(0), _endPos(0) {
+MoviePlayer::MoviePlayer(ToltecsEngine *vm) : _vm(vm), _isPlaying(false), _lastPrefetchOfs(0), _framesPerSoundChunk(0), _endPos(0), _audioStream(0) {
}
MoviePlayer::~MoviePlayer() {
diff --git a/engines/toltecs/movie.h b/engines/toltecs/movie.h
index 9404e5f639..8c6348d700 100644
--- a/engines/toltecs/movie.h
+++ b/engines/toltecs/movie.h
@@ -23,9 +23,12 @@
#ifndef TOLTECS_MOVIE_H
#define TOLTECS_MOVIE_H
-#include "audio/audiostream.h"
#include "audio/mixer.h" // for Audio::SoundHandle
+namespace Audio {
+class QueuingAudioStream;
+}
+
namespace Toltecs {
class MoviePlayer {
diff --git a/engines/toltecs/resource.cpp b/engines/toltecs/resource.cpp
index 468ae0272f..6dbb9c2843 100644
--- a/engines/toltecs/resource.cpp
+++ b/engines/toltecs/resource.cpp
@@ -31,6 +31,7 @@ namespace Toltecs {
/* ArchiveReader */
ArchiveReader::ArchiveReader() {
+ _offsets = 0;
}
ArchiveReader::~ArchiveReader() {
diff --git a/engines/toltecs/segmap.cpp b/engines/toltecs/segmap.cpp
index b27e0c8e11..d50e110485 100644
--- a/engines/toltecs/segmap.cpp
+++ b/engines/toltecs/segmap.cpp
@@ -27,6 +27,11 @@
namespace Toltecs {
SegmentMap::SegmentMap(ToltecsEngine *vm) : _vm(vm) {
+ _maskRectData = NULL;
+ memset(_deadEndPathRects, 0, sizeof(_closedPathRects));
+ _closedPathRectsCount = 0;
+ _deadEndPathRectsCount = 0;
+ _pathNodesCount = 0;
}
SegmentMap::~SegmentMap() {
diff --git a/engines/toltecs/segmap.h b/engines/toltecs/segmap.h
index c1ad293162..03bd858217 100644
--- a/engines/toltecs/segmap.h
+++ b/engines/toltecs/segmap.h
@@ -80,6 +80,8 @@ public: // for debugging purposes
struct PathPoint {
int16 y, x;
+
+ PathPoint() : x(0), y(0) {}
};
typedef Common::Array<SegmapMaskRect> SegmapMaskRectArray;
diff --git a/engines/toltecs/sprite.cpp b/engines/toltecs/sprite.cpp
index f29f64dcfe..be4be5d9e3 100644
--- a/engines/toltecs/sprite.cpp
+++ b/engines/toltecs/sprite.cpp
@@ -84,6 +84,7 @@ public:
_yerror = _sprite->yerror;
_origHeight = _sprite->origHeight;
_scalerStatus = 0;
+ _xerror = 0;
}
SpriteReaderStatus readPacket(PixelPacket &packet) {
SpriteReaderStatus status = kSrsPixelsLeft;
@@ -135,6 +136,8 @@ public:
_yerror = _sprite->yerror;
_origHeight = _sprite->origHeight;
_scalerStatus = 0;
+ _sourcep = 0;
+ _xerror = 0;
}
SpriteReaderStatus readPacket(PixelPacket &packet) {
SpriteReaderStatus status;
diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h
index 7a04f6e8da..ece82f4a1a 100644
--- a/engines/toltecs/toltecs.h
+++ b/engines/toltecs/toltecs.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TOLTECS_H
-#define TOLTECS_H
+#ifndef TOLTECS_TOLTECS_H
+#define TOLTECS_TOLTECS_H
#include "common/scummsys.h"
#include "common/endian.h"
@@ -231,4 +231,4 @@ public:
} // End of namespace Toltecs
-#endif /* TOLTECS_H */
+#endif /* TOLTECS_TOLTECS_H */
diff --git a/engines/tony/configure.engine b/engines/tony/configure.engine
index f85f45d158..2df4434982 100644
--- a/engines/tony/configure.engine
+++ b/engines/tony/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit"
+add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit highres"
diff --git a/engines/tony/font.cpp b/engines/tony/font.cpp
index 850aff17be..fb40bf5c67 100644
--- a/engines/tony/font.cpp
+++ b/engines/tony/font.cpp
@@ -921,6 +921,12 @@ RMDialogChoice::RMDialogChoice() {
_curAdded = 0;
_bShow = false;
+
+ _curSelection = 0;
+ _numChoices = 0;
+
+ _drawedStrings = NULL;
+ _ptDrawStrings = NULL;
}
RMDialogChoice::~RMDialogChoice() {
diff --git a/engines/tony/game.cpp b/engines/tony/game.cpp
index 0a2c62330b..7b9cb4c6ca 100644
--- a/engines/tony/game.cpp
+++ b/engines/tony/game.cpp
@@ -319,6 +319,11 @@ RMOptionScreen::RMOptionScreen() {
_fadeTime = 0;
_nEditPos = 0;
_nLastState = MENUGAME;
+
+ _bExit = false;
+ _bLoadMenuOnly = false;
+ _bNoLoadSave = false;
+ _bAlterGfx = false;
}
RMOptionScreen::~RMOptionScreen() {
@@ -1145,7 +1150,7 @@ void RMOptionScreen::doFrame(CORO_PARAM, RMInput *input) {
// Turn on edit mode
_bEditSaveName = true;
_nEditPos = _ctx->i;
- strcpy(_editName, _curThumbName[_ctx->i].c_str());
+ Common::strlcpy(_editName, _curThumbName[_ctx->i].c_str(), sizeof(_editName));
_ctx->bRefresh = true;
}
diff --git a/engines/tony/gfxcore.cpp b/engines/tony/gfxcore.cpp
index 2a32926c53..27145d7c4b 100644
--- a/engines/tony/gfxcore.cpp
+++ b/engines/tony/gfxcore.cpp
@@ -1733,13 +1733,6 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 5;
b /= 5;
- if (r > 0x1f)
- r = 0x1f;
- if (g > 0x3f)
- g = 0x3f;
- if (b > 0x1f)
- b = 0x1f;
-
mybuf[0] = (r << 11) | (g << 5) | b;
}
}
@@ -1774,13 +1767,6 @@ void RMGfxSourceBuffer8AA::drawAA(RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *pri
g /= 6;
b /= 6;
- if (r > 0x1f)
- r = 0x1f;
- if (g > 0x3f)
- g = 0x3f;
- if (b > 0x1f)
- b = 0x1f;
-
mybuf[0] = (r << 11) | (g << 5) | b;
}
}
diff --git a/engines/tony/gfxcore.h b/engines/tony/gfxcore.h
index c9081506d7..1a0738e5b7 100644
--- a/engines/tony/gfxcore.h
+++ b/engines/tony/gfxcore.h
@@ -442,6 +442,7 @@ private:
OTList();
OTList(RMGfxPrimitive *pr) {
_prim = pr;
+ _next = NULL;
}
};
diff --git a/engines/tony/mpal/loadmpc.cpp b/engines/tony/mpal/loadmpc.cpp
index 8d030f1e52..01892a40e6 100644
--- a/engines/tony/mpal/loadmpc.cpp
+++ b/engines/tony/mpal/loadmpc.cpp
@@ -331,7 +331,7 @@ static const byte *parseItem(const byte *lpBuf, LpMpalItem lpmiItem) {
byte len = *lpBuf;
lpBuf++;
- memcpy(lpmiItem->_lpszDescribe, lpBuf, MIN((byte)127, len));
+ memcpy(lpmiItem->_lpszDescribe, lpBuf, MIN((byte)MAX_DESCRIBE_SIZE, len));
lpBuf += len;
if (len >= MAX_DESCRIBE_SIZE)
diff --git a/engines/tony/mpal/mpal.cpp b/engines/tony/mpal/mpal.cpp
index 89cc28130d..9172843781 100644
--- a/engines/tony/mpal/mpal.cpp
+++ b/engines/tony/mpal/mpal.cpp
@@ -367,12 +367,18 @@ MpalHandle resLoad(uint32 dwId) {
temp = (byte *)globalAlloc(GMEM_FIXED | GMEM_ZEROINIT, nSizeComp);
nBytesRead = GLOBALS._hMpr.read(temp, nSizeComp);
- if (nBytesRead != nSizeComp)
+ if (nBytesRead != nSizeComp) {
+ globalDestroy(temp);
+ globalDestroy(h);
return NULL;
+ }
lzo1x_decompress(temp, nSizeComp, buf, &nBytesRead);
- if (nBytesRead != nSizeDecomp)
+ if (nBytesRead != nSizeDecomp) {
+ globalDestroy(temp);
+ globalDestroy(h);
return NULL;
+ }
globalDestroy(temp);
globalUnlock(h);
@@ -526,8 +532,10 @@ static LpItem getItemData(uint32 nOrdItem) {
globalFree(hDat);
// Check if we've got to the end of the file
- if (i != 0xABCD)
+ if (i != 0xABCD) {
+ globalDestroy(ret);
return NULL;
+ }
return ret;
}
@@ -1413,36 +1421,51 @@ bool mpalInit(const char *lpszMpcFileName, const char *lpszMprFileName,
if (bCompress) {
// Get the compressed size and read the data in
uint32 dwSizeComp = hMpc.readUint32LE();
- if (hMpc.err())
+ if (hMpc.err()) {
+ globalDestroy(lpMpcImage);
return false;
+ }
cmpbuf = (byte *)globalAlloc(GMEM_FIXED, dwSizeComp);
- if (cmpbuf == NULL)
+ if (cmpbuf == NULL) {
+ globalDestroy(lpMpcImage);
return false;
+ }
nBytesRead = hMpc.read(cmpbuf, dwSizeComp);
- if (nBytesRead != dwSizeComp)
+ if (nBytesRead != dwSizeComp) {
+ globalDestroy(cmpbuf);
+ globalDestroy(lpMpcImage);
return false;
+ }
// Decompress the data
lzo1x_decompress(cmpbuf, dwSizeComp, lpMpcImage, &nBytesRead);
- if (nBytesRead != dwSizeDecomp)
+ if (nBytesRead != dwSizeDecomp) {
+ globalDestroy(cmpbuf);
+ globalDestroy(lpMpcImage);
return false;
+ }
globalDestroy(cmpbuf);
} else {
// If the file is not compressed, we directly read in the data
nBytesRead = hMpc.read(lpMpcImage, dwSizeDecomp);
- if (nBytesRead != dwSizeDecomp)
+ if (nBytesRead != dwSizeDecomp) {
+ globalDestroy(lpMpcImage);
return false;
+ }
}
// Close the file
hMpc.close();
// Process the data
- if (parseMpc(lpMpcImage) == false)
+ if (parseMpc(lpMpcImage) == false) {
+ globalDestroy(lpMpcImage);
+
return false;
+ }
globalDestroy(lpMpcImage);
diff --git a/engines/tony/mpal/mpalutils.cpp b/engines/tony/mpal/mpalutils.cpp
index 84c8a68919..d52e7332cc 100644
--- a/engines/tony/mpal/mpalutils.cpp
+++ b/engines/tony/mpal/mpalutils.cpp
@@ -37,6 +37,8 @@ namespace MPAL {
* @param resId MPAL resource to open
*/
RMRes::RMRes(uint32 resID) {
+ _buf = NULL;
+
_h = g_vm->_resUpdate.queryResource(resID);
if (_h == NULL)
_h = mpalQueryResource(resID);
diff --git a/engines/tony/sound.cpp b/engines/tony/sound.cpp
index aa86750ad5..fed51dacf4 100644
--- a/engines/tony/sound.cpp
+++ b/engines/tony/sound.cpp
@@ -161,6 +161,7 @@ FPSfx::FPSfx(bool soundOn) {
_loopStream = 0;
_rewindableStream = 0;
_paused = false;
+ _loop = 0;
g_vm->_activeSfx.push_back(this);
}
diff --git a/engines/tony/tony.cpp b/engines/tony/tony.cpp
index d8fa45cb5d..c51f449aa1 100644
--- a/engines/tony/tony.cpp
+++ b/engines/tony/tony.cpp
@@ -83,6 +83,8 @@ TonyEngine::TonyEngine(OSystem *syst, const TonyGameDescription *gameDesc) : Eng
_bTimeFreezed = false;
_nTimeFreezed = 0;
_vdbCodec = FPCODEC_UNKNOWN;
+
+ memset(_funcList, 0, sizeof(_funcList));
}
TonyEngine::~TonyEngine() {
diff --git a/engines/tony/tony.h b/engines/tony/tony.h
index 40bace8db8..fc47e1a1bf 100644
--- a/engines/tony/tony.h
+++ b/engines/tony/tony.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TONY_H
-#define TONY_H
+#ifndef TONY_TONY_H
+#define TONY_TONY_H
#include "common/scummsys.h"
#include "common/system.h"
@@ -242,4 +242,4 @@ extern TonyEngine *g_vm;
} // End of namespace Tony
-#endif /* TONY_H */
+#endif /* TONY_TONY_H */
diff --git a/engines/toon/configure.engine b/engines/toon/configure.engine
index 00c98f7d8a..689bce1c02 100644
--- a/engines/toon/configure.engine
+++ b/engines/toon/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine toon "Toonstruck" yes
+add_engine toon "Toonstruck" yes "" "" "highres"
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
index 2ca2bce2ee..5d2e0a9bca 100644
--- a/engines/toon/detection.cpp
+++ b/engines/toon/detection.cpp
@@ -127,7 +127,7 @@ static const char * const directoryGlobs[] = {
class ToonMetaEngine : public AdvancedMetaEngine {
public:
ToonMetaEngine() : AdvancedMetaEngine(Toon::gameDescriptions, sizeof(ADGameDescription), toonGames) {
- _singleid = "toon";
+ _singleId = "toon";
_maxScanDepth = 3;
_directoryGlobs = directoryGlobs;
}
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
index 3ab23a1e51..837339402c 100644
--- a/engines/toon/toon.cpp
+++ b/engines/toon/toon.cpp
@@ -35,7 +35,6 @@
#include "graphics/surface.h"
#include "graphics/thumbnail.h"
#include "gui/saveload.h"
-#include "gui/about.h"
#include "gui/message.h"
#include "toon/resource.h"
#include "toon/toon.h"
@@ -709,7 +708,7 @@ bool ToonEngine::showOptions() {
entries[2].activeFrame = entries[2].animation->_numFrames - 1;
if (!_showConversationText) {
- entries[4].activeFrame = 4;
+ entries[4].activeFrame = 4;
} else if (_useAlternativeFont) {
entries[4].activeFrame = 8;
} else {
@@ -798,19 +797,19 @@ bool ToonEngine::showOptions() {
// handle sliders
if (clickingOn == OPTIONMENUHOTSPOT_VOLUMEMUSICSLIDER) {
entries[clickingOnSprite].activeFrame = ratioX * (entries[clickingOnSprite].animation->_numFrames) / 256;
- int vol = entries[clickingOnSprite].activeFrame * 256 / entries[clickingOnSprite].animation->_numFrames;
+ int vol = entries[clickingOnSprite].activeFrame * 256 / entries[clickingOnSprite].animation->_numFrames;
_audioManager->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol);
}
if (clickingOn == OPTIONMENUHOTSPOT_VOLUMEVOICESLIDER) {
entries[clickingOnSprite].activeFrame = ratioX * (entries[clickingOnSprite].animation->_numFrames) / 256;
- int vol = entries[clickingOnSprite].activeFrame * 256 / entries[clickingOnSprite].animation->_numFrames;
+ int vol = entries[clickingOnSprite].activeFrame * 256 / entries[clickingOnSprite].animation->_numFrames;
_audioManager->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol);
}
if (clickingOn == OPTIONMENUHOTSPOT_VOLUMESFXSLIDER) {
entries[clickingOnSprite].activeFrame = ratioX * (entries[clickingOnSprite].animation->_numFrames) / 256;
- int vol = entries[clickingOnSprite].activeFrame * 256 / entries[clickingOnSprite].animation->_numFrames;
+ int vol = entries[clickingOnSprite].activeFrame * 256 / entries[clickingOnSprite].animation->_numFrames;
_audioManager->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol);
}
@@ -936,10 +935,12 @@ bool ToonEngine::showOptions() {
_gameState->_inMenu = false;
_firstFrame = true;
_gameState->_currentScrollValue = oldScrollValue;
-
+
restorePalette();
dirtyAllScreen();
+ delete optionPicture;
+
return exitGame;
}
@@ -1297,6 +1298,7 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
_scriptState[i].running = false;
}
_currentScriptRegion = 0;
+ _currentFont = nullptr;
}
ToonEngine::~ToonEngine() {
diff --git a/engines/touche/configure.engine b/engines/touche/configure.engine
index 777578e623..f35940ef47 100644
--- a/engines/touche/configure.engine
+++ b/engines/touche/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes
+add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes "" "" "highres"
diff --git a/engines/touche/detection.cpp b/engines/touche/detection.cpp
index 1d0e136d69..dcb58ffae6 100644
--- a/engines/touche/detection.cpp
+++ b/engines/touche/detection.cpp
@@ -128,7 +128,7 @@ class ToucheMetaEngine : public AdvancedMetaEngine {
public:
ToucheMetaEngine() : AdvancedMetaEngine(Touche::gameDescriptions, sizeof(ADGameDescription), toucheGames) {
_md5Bytes = 4096;
- _singleid = "touche";
+ _singleId = "touche";
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
index ff4f41f44d..bb21f399c6 100644
--- a/engines/touche/touche.cpp
+++ b/engines/touche/touche.cpp
@@ -32,6 +32,7 @@
#include "common/keyboard.h"
#include "common/textconsole.h"
+#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "engines/util.h"
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
index 3de5b8caf2..c76532b302 100644
--- a/engines/touche/touche.h
+++ b/engines/touche/touche.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TOUCHE_ENGINE_H
-#define TOUCHE_ENGINE_H
+#ifndef TOUCHE_TOUCHE_H
+#define TOUCHE_TOUCHE_H
#include "common/array.h"
#include "common/endian.h"
@@ -31,7 +31,6 @@
#include "common/util.h"
#include "audio/mixer.h"
-#include "audio/audiostream.h"
#include "engines/engine.h"
diff --git a/engines/tsage/blue_force/blueforce_dialogs.cpp b/engines/tsage/blue_force/blueforce_dialogs.cpp
index 5be27c9ae7..99db61b64d 100644
--- a/engines/tsage/blue_force/blueforce_dialogs.cpp
+++ b/engines/tsage/blue_force/blueforce_dialogs.cpp
@@ -20,9 +20,6 @@
*
*/
-#include "gui/dialog.h"
-#include "gui/widget.h"
-
#include "tsage/tsage.h"
#include "tsage/core.h"
#include "tsage/dialogs.h"
@@ -161,7 +158,7 @@ void RightClickDialog::execute() {
}
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
// Deactivate the graphics manager used for the dialog
@@ -242,7 +239,7 @@ void AmmoBeltDialog::execute() {
}
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
_gfxManager.deactivate();
diff --git a/engines/tsage/blue_force/blueforce_dialogs.h b/engines/tsage/blue_force/blueforce_dialogs.h
index 77017db9d0..38ec7a7828 100644
--- a/engines/tsage/blue_force/blueforce_dialogs.h
+++ b/engines/tsage/blue_force/blueforce_dialogs.h
@@ -23,13 +23,10 @@
#ifndef TSAGE_BLUEFORCE_DIALOGS_H
#define TSAGE_BLUEFORCE_DIALOGS_H
-#include "gui/options.h"
+#include "tsage/core.h"
#include "tsage/dialogs.h"
#include "tsage/events.h"
#include "tsage/graphics.h"
-#include "common/list.h"
-#include "common/rect.h"
-#include "common/system.h"
namespace TsAGE {
diff --git a/engines/tsage/blue_force/blueforce_logic.cpp b/engines/tsage/blue_force/blueforce_logic.cpp
index e6e71399dc..2c5f9bd738 100644
--- a/engines/tsage/blue_force/blueforce_logic.cpp
+++ b/engines/tsage/blue_force/blueforce_logic.cpp
@@ -859,7 +859,7 @@ void SceneExt::endStrip() {
}
void SceneExt::clearScreen() {
- BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0);
+ BF_GLOBALS._screen.clear();
}
/*--------------------------------------------------------------------------*/
@@ -1411,7 +1411,7 @@ void SceneMessage::process(Event &event) {
void SceneMessage::draw() {
- GfxSurface &surface = BF_GLOBALS._screenSurface;
+ GfxSurface &surface = BF_GLOBALS._screen;
// Clear the game area
surface.fillRect(Rect(0, 0, SCREEN_WIDTH, UI_INTERFACE_Y), 0);
diff --git a/engines/tsage/blue_force/blueforce_scenes1.cpp b/engines/tsage/blue_force/blueforce_scenes1.cpp
index 1cbebd140e..6c37d18cc7 100644
--- a/engines/tsage/blue_force/blueforce_scenes1.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes1.cpp
@@ -22,6 +22,7 @@
#include "common/config-manager.h"
#include "tsage/blue_force/blueforce_scenes1.h"
+#include "tsage/dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
diff --git a/engines/tsage/blue_force/blueforce_scenes4.cpp b/engines/tsage/blue_force/blueforce_scenes4.cpp
index 50f8499b3b..7c5b41092c 100644
--- a/engines/tsage/blue_force/blueforce_scenes4.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes4.cpp
@@ -21,7 +21,6 @@
*/
#include "tsage/blue_force/blueforce_scenes4.h"
-#include "tsage/blue_force/blueforce_dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
diff --git a/engines/tsage/blue_force/blueforce_scenes5.cpp b/engines/tsage/blue_force/blueforce_scenes5.cpp
index 562facd000..b757860dda 100644
--- a/engines/tsage/blue_force/blueforce_scenes5.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes5.cpp
@@ -21,7 +21,6 @@
*/
#include "tsage/blue_force/blueforce_scenes5.h"
-#include "tsage/blue_force/blueforce_dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
diff --git a/engines/tsage/blue_force/blueforce_scenes6.cpp b/engines/tsage/blue_force/blueforce_scenes6.cpp
index 92534d3095..921b2c89d0 100644
--- a/engines/tsage/blue_force/blueforce_scenes6.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes6.cpp
@@ -21,7 +21,6 @@
*/
#include "tsage/blue_force/blueforce_scenes6.h"
-#include "tsage/blue_force/blueforce_dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
@@ -78,7 +77,7 @@ void Scene600::Action1::signal() {
pObj->animate(ANIM_MODE_NONE, NULL);
}
- BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0);
+ BF_GLOBALS._screen.fillRect(BF_GLOBALS._screen.getBounds(), 0);
scene->loadScene(999);
setDelay(5);
break;
@@ -275,7 +274,7 @@ void Scene666::postInit(SceneObjectList *OwnerList) {
SceneExt::postInit();
BF_GLOBALS._interfaceY = SCREEN_HEIGHT;
loadScene(999);
- BF_GLOBALS._screenSurface.fillRect(BF_GLOBALS._screenSurface.getBounds(), 0);
+ BF_GLOBALS._screen.fillRect(BF_GLOBALS._screen.getBounds(), 0);
if (BF_GLOBALS._dayNumber == 0) {
BF_GLOBALS._dayNumber = 1;
diff --git a/engines/tsage/blue_force/blueforce_scenes8.cpp b/engines/tsage/blue_force/blueforce_scenes8.cpp
index 337e73dad0..15767215c5 100644
--- a/engines/tsage/blue_force/blueforce_scenes8.cpp
+++ b/engines/tsage/blue_force/blueforce_scenes8.cpp
@@ -21,7 +21,6 @@
*/
#include "tsage/blue_force/blueforce_scenes8.h"
-#include "tsage/blue_force/blueforce_dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp
index d1faca5dac..7240c91720 100644
--- a/engines/tsage/converse.cpp
+++ b/engines/tsage/converse.cpp
@@ -469,7 +469,7 @@ int ConversationChoiceDialog::execute(const Common::StringArray &choiceList) {
while (!g_globals->_events.getEvent(event, EVENT_KEYPRESS | EVENT_BUTTON_DOWN | EVENT_MOUSE_MOVE) &&
!g_vm->shouldQuit()) {
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
if (g_vm->shouldQuit())
break;
diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp
index d4068c25c9..985d16b031 100644
--- a/engines/tsage/core.cpp
+++ b/engines/tsage/core.cpp
@@ -1467,7 +1467,7 @@ void ScenePalette::fade(const byte *adjustData, bool fullAdjust, int percent) {
// Set the altered palette
g_system->getPaletteManager()->setPalette((const byte *)&tempPalette[0], 0, 256);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
PaletteRotation *ScenePalette::addRotation(int start, int end, int rotationMode, int duration, Action *action) {
@@ -1524,11 +1524,11 @@ void ScenePalette::changeBackground(const Rect &bounds, FadeMode fadeMode) {
if (g_vm->getGameID() != GType_Ringworld && g_vm->getGameID() != GType_Sherlock1)
tempRect.setHeight(T2_GLOBALS._interfaceY);
- g_globals->_screenSurface.copyFrom(g_globals->_sceneManager._scene->_backSurface,
+ g_globals->_screen.copyFrom(g_globals->_sceneManager._scene->_backSurface,
tempRect, Rect(0, 0, tempRect.width(), tempRect.height()), NULL);
if (g_vm->getGameID() == GType_Ringworld2 && !GLOBALS._player._uiEnabled
&& T2_GLOBALS._interfaceY == UI_INTERFACE_Y) {
- g_globals->_screenSurface.fillRect(Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT - 1), 0);
+ g_globals->_screen.fillRect(Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT - 1), 0);
}
for (SynchronizedList<PaletteModifier *>::iterator i = tempPalette._listeners.begin(); i != tempPalette._listeners.end(); ++i)
@@ -1796,7 +1796,7 @@ void SceneItem::display(int resNum, int lineNum, ...) {
// Keep event on-screen until a mouse or keypress
while (!g_vm->shouldQuit() && !g_globals->_events.getEvent(event,
EVENT_BUTTON_DOWN | EVENT_KEYPRESS)) {
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
if ((g_vm->getGameID() == GType_Ringworld2) && (R2_GLOBALS._speechSubtitles & SPEECH_VOICE)) {
@@ -2816,7 +2816,7 @@ void SceneObject::updateScreen() {
destRect.translate(-sceneBounds.left, -sceneBounds.top);
srcRect.translate(-g_globals->_sceneOffset.x, -g_globals->_sceneOffset.y);
- g_globals->_screenSurface.copyFrom(g_globals->_sceneManager._scene->_backSurface, srcRect, destRect);
+ g_globals->_screen.copyFrom(g_globals->_sceneManager._scene->_backSurface, srcRect, destRect);
}
}
diff --git a/engines/tsage/detection.cpp b/engines/tsage/detection.cpp
index 7784a3de1a..584ad87742 100644
--- a/engines/tsage/detection.cpp
+++ b/engines/tsage/detection.cpp
@@ -40,7 +40,7 @@ struct tSageGameDescription {
};
const char *TSageEngine::getGameId() const {
- return _gameDescription->desc.gameid;
+ return _gameDescription->desc.gameId;
}
uint32 TSageEngine::getGameID() const {
@@ -75,7 +75,7 @@ enum {
class TSageMetaEngine : public AdvancedMetaEngine {
public:
TSageMetaEngine() : AdvancedMetaEngine(TsAGE::gameDescriptions, sizeof(TsAGE::tSageGameDescription), tSageGameTitles) {
- _singleid = "tsage";
+ _singleId = "tsage";
}
virtual const char *getName() const {
@@ -83,7 +83,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "(c) Tsunami Media";
+ return "(C) Tsunami Media";
}
virtual bool hasFeature(MetaEngineFeature f) const {
diff --git a/engines/tsage/dialogs.cpp b/engines/tsage/dialogs.cpp
index dd4bc6aa86..3704ce1f04 100644
--- a/engines/tsage/dialogs.cpp
+++ b/engines/tsage/dialogs.cpp
@@ -23,6 +23,7 @@
#include "common/translation.h"
#include "gui/dialog.h"
+#include "gui/options.h"
#include "gui/widget.h"
#include "tsage/tsage.h"
@@ -91,6 +92,11 @@ int MessageDialog::show2(const Common::String &message, const Common::String &bt
/*--------------------------------------------------------------------------*/
+class ConfigDialog : public GUI::OptionsDialog {
+public:
+ ConfigDialog();
+};
+
ConfigDialog::ConfigDialog() : GUI::OptionsDialog("", "GlobalConfig") {
//
// Sound controllers
diff --git a/engines/tsage/dialogs.h b/engines/tsage/dialogs.h
index 8ab37f6c93..33a5fa47a4 100644
--- a/engines/tsage/dialogs.h
+++ b/engines/tsage/dialogs.h
@@ -23,7 +23,6 @@
#ifndef TSAGE_DIALOGS_H
#define TSAGE_DIALOGS_H
-#include "gui/options.h"
#include "tsage/events.h"
#include "tsage/graphics.h"
#include "common/list.h"
@@ -44,11 +43,6 @@ public:
static int show2(const Common::String &message, const Common::String &btn1Message, const Common::String &btn2Message = Common::String());
};
-class ConfigDialog : public GUI::OptionsDialog {
-public:
- ConfigDialog();
-};
-
/*--------------------------------------------------------------------------*/
class ModalDialog : public GfxDialog {
diff --git a/engines/tsage/events.cpp b/engines/tsage/events.cpp
index 0491c043a4..1fa17022de 100644
--- a/engines/tsage/events.cpp
+++ b/engines/tsage/events.cpp
@@ -50,7 +50,7 @@ bool EventsClass::pollEvent() {
++_frameNumber;
// Update screen
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
if (!g_system->getEventManager()->pollEvent(_event)) return false;
@@ -400,7 +400,7 @@ void EventsClass::delay(int numFrames) {
_priorFrameTime = g_system->getMillis();
}
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
_prevDelayFrame = _frameNumber;
_priorFrameTime = g_system->getMillis();
}
diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp
index b880f35007..b95bea3b23 100644
--- a/engines/tsage/globals.cpp
+++ b/engines/tsage/globals.cpp
@@ -59,7 +59,7 @@ static SavedObject *classFactoryProc(const Common::String &className) {
/*--------------------------------------------------------------------------*/
-Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface),
+Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screen),
_randomSource("tsage"), _color1(0), _color2(255), _color3(255) {
reset();
_stripNum = 0;
@@ -119,7 +119,7 @@ Globals::Globals() : _dialogCenter(160, 140), _gfxManagerInstance(_screenSurface
_color3 = 4;
_dialogCenter.y = 100;
}
- _screenSurface.setScreenSurface();
+
_gfxManagers.push_back(&_gfxManagerInstance);
_sceneObjects = &_sceneObjectsInstance;
diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h
index 1194fe8b9c..8a441db922 100644
--- a/engines/tsage/globals.h
+++ b/engines/tsage/globals.h
@@ -25,11 +25,11 @@
#include "common/random.h"
#include "tsage/core.h"
-#include "tsage/dialogs.h"
#include "tsage/scenes.h"
#include "tsage/events.h"
#include "tsage/sound.h"
#include "tsage/saveload.h"
+#include "tsage/screen.h"
#include "tsage/user_interface.h"
namespace TsAGE {
@@ -38,7 +38,7 @@ class Globals : public SavedObject {
private:
static void dispatchSound(ASound *obj);
public:
- GfxSurface _screenSurface;
+ Screen _screen;
GfxManager _gfxManagerInstance;
Common::List<GfxManager *> _gfxManagers;
SceneHandler *_sceneHandler;
diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp
index 156503fb51..7b7b41f0aa 100644
--- a/engines/tsage/graphics.cpp
+++ b/engines/tsage/graphics.cpp
@@ -229,123 +229,45 @@ void Rect::synchronize(Serializer &s) {
/*--------------------------------------------------------------------------*/
-GfxSurface::GfxSurface() : _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) {
+GfxSurface::GfxSurface() : Graphics::Screen(0, 0), _bounds(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_disableUpdates = false;
_lockSurfaceCtr = 0;
- _customSurface = NULL;
_transColor = -1;
- _trackDirtyRects = false;
_flags = 0;
}
-GfxSurface::GfxSurface(const GfxSurface &s) {
+GfxSurface::GfxSurface(const GfxSurface &s): Graphics::Screen(0, 0) {
+ free(); // Free the 0x0 surface allocated by Graphics::Screen
_lockSurfaceCtr = 0;
- _customSurface = NULL;
- _trackDirtyRects = false;
- *this = s;
+
+ operator=(s);
}
GfxSurface::~GfxSurface() {
- clear();
+ // Sanity check.. GfxSurface should always be just referencing _rawSurface,
+ // and not directly managing it's own surface
+ assert(disposeAfterUse() == DisposeAfterUse::NO);
}
-void GfxSurface::clear() {
- if (_customSurface) {
- _customSurface->free();
- delete _customSurface;
- _customSurface = NULL;
- }
-}
-
-/**
- * Specifies that the surface will encapsulate the ScummVM screen surface
- */
-void GfxSurface::setScreenSurface() {
- _trackDirtyRects = true;
- create(SCREEN_WIDTH, SCREEN_HEIGHT);
-}
-
-/**
- * Updates the physical screen with the screen surface buffer
- */
-void GfxSurface::updateScreen() {
- assert(_trackDirtyRects);
-
- // Merge any overlapping dirty rects
- mergeDirtyRects();
-
- // Loop through the dirty rect list to copy the affected areas to the sc
- for (Common::List<Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) {
- Rect r = *i;
-
- // Make sure that there is something to update. If not, skip this
- // rectangle. An example case is the speedbike closeup at the beginning
- // of Ringworld (third screen).
- if (r.isEmpty())
- continue;
-
- const byte *srcP = (const byte *)_customSurface->getBasePtr(r.left, r.top);
- g_system->copyRectToScreen(srcP, _customSurface->pitch, r.left, r.top,
- r.width(), r.height());
- }
-
- // Update the physical screen
- g_system->updateScreen();
-
- // Now that the dirty rects have been copied, clear the dirty rect list
- _dirtyRects.clear();
-}
+void GfxSurface::create(uint16 width, uint16 height) {
+ free();
-/**
- * Adds a rect to the dirty rect list
- */
-void GfxSurface::addDirtyRect(const Rect &r) {
- if (_trackDirtyRects) {
- // Get the bounds and adjust to allow for sub-screen areas
- Rect r2 = r;
- r2.translate(_bounds.left, _bounds.top);
-
- // Add to the dirty rect list
- r2.right = MIN(r2.right + 1, SCREEN_WIDTH);
- r2.bottom = MIN(r2.bottom + 1, SCREEN_HEIGHT);
-
- if (r2.isValidRect())
- _dirtyRects.push_back(r2);
- }
+ _rawSurface.create(width, height);
+ setBounds(Rect(0, 0, width, height));
}
-
-
-/**
- * Specifies that the surface should maintain it's own internal surface
- */
-void GfxSurface::create(int width, int height) {
- assert((width >= 0) && (height >= 0));
-
- if (_customSurface) {
- _customSurface->free();
- delete _customSurface;
- }
- _customSurface = new Graphics::Surface();
- _customSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
- Common::fill((byte *)_customSurface->getPixels(), (byte *)_customSurface->getBasePtr(0, height), 0);
- _bounds = Rect(0, 0, width, height);
+void GfxSurface::setBounds(const Rect &bounds) {
+ _bounds = bounds;
+ Graphics::ManagedSurface::create(_rawSurface, bounds);
}
/**
* Locks the surface for access, and returns a raw ScummVM surface to manipulate it
*/
-Graphics::Surface GfxSurface::lockSurface() {
+Graphics::ManagedSurface &GfxSurface::lockSurface() {
++_lockSurfaceCtr;
-
- Graphics::Surface *src = _customSurface;
- assert(src);
-
- // Setup the returned surface either as one pointing to the same pixels as the source, or
- // as a subset of the source one based on the currently set bounds
- Graphics::Surface result;
- result.init(_bounds.width(), _bounds.height(), src->pitch, src->getBasePtr(_bounds.left, _bounds.top), src->format);
- return result;
+ return *this;
}
/**
@@ -367,69 +289,43 @@ void GfxSurface::synchronize(Serializer &s) {
if (s.isSaving()) {
// Save contents of the surface
- if (_customSurface) {
- s.syncAsSint16LE(_customSurface->w);
- s.syncAsSint16LE(_customSurface->h);
- s.syncBytes((byte *)_customSurface->getPixels(), _customSurface->w * _customSurface->h);
+ if (disposeAfterUse() == DisposeAfterUse::YES) {
+ s.syncAsSint16LE(this->w);
+ s.syncAsSint16LE(this->h);
+ s.syncBytes((byte *)getPixels(), this->w * this->h);
} else {
int zero = 0;
s.syncAsSint16LE(zero);
s.syncAsSint16LE(zero);
}
} else {
- int w = 0, h = 0;
- s.syncAsSint16LE(w);
- s.syncAsSint16LE(h);
-
- if ((w == 0) || (h == 0)) {
- if (_customSurface)
- delete _customSurface;
- _customSurface = NULL;
+ int xSize = 0, ySize = 0;
+ s.syncAsSint16LE(xSize);
+ s.syncAsSint16LE(ySize);
+
+ if (xSize == 0 || ySize == 0) {
+ free();
} else {
- create(w, h);
- s.syncBytes((byte *)_customSurface->getPixels(), w * h);
+ create(xSize, ySize);
+ s.syncBytes((byte *)getPixels(), xSize * ySize);
}
}
}
-/**
- * Fills a specified rectangle on the surface with the specified color
- *
- * @bounds Area to fill
- * @color Color to use
- */
-void GfxSurface::fillRect(const Rect &bounds, int color) {
- Graphics::Surface surface = lockSurface();
- surface.fillRect(bounds, color);
- unlockSurface();
- addDirtyRect(bounds);
-}
-
GfxSurface &GfxSurface::operator=(const GfxSurface &s) {
assert(_lockSurfaceCtr == 0);
assert(s._lockSurfaceCtr == 0);
- if (_customSurface) {
- _customSurface->free();
- delete _customSurface;
- }
-
- _customSurface = s._customSurface;
_disableUpdates = s._disableUpdates;
_bounds = s._bounds;
_centroid = s._centroid;
_transColor = s._transColor;
_flags = s._flags;
- if (_customSurface) {
- // Surface owns the internal data, so replicate it so new surface owns it's own
- _customSurface = new Graphics::Surface();
- _customSurface->create(s._customSurface->w, s._customSurface->h, Graphics::PixelFormat::createFormatCLUT8());
- const byte *srcP = (const byte *)s._customSurface->getPixels();
- byte *destP = (byte *)_customSurface->getPixels();
-
- Common::copy(srcP, srcP + (_bounds.width() * _bounds.height()), destP);
- }
+ // Copy the source's surface
+ create(s.w, s.h);
+ blitFrom(s);
+ setBounds(s.getBounds());
return *this;
}
@@ -474,7 +370,7 @@ bool GfxSurface::displayText(const Common::String &msg, const Common::Point &pt)
/**
* Loads a quarter of a screen from a resource
*/
-void GfxSurface::loadScreenSection(Graphics::Surface &dest, int xHalf, int yHalf, int xSection, int ySection) {
+void GfxSurface::loadScreenSection(Graphics::ManagedSurface &dest, int xHalf, int yHalf, int xSection, int ySection) {
int screenNum = g_globals->_sceneManager._scene->_activeScreenNumber;
Rect updateRect(0, 0, 160, 100);
updateRect.translate(xHalf * 160, yHalf * 100);
@@ -682,50 +578,6 @@ void GfxSurface::draw(const Common::Point &pt, Rect *rect) {
}
}
-/**
- * Merges any clipping rectangles that overlap to try and reduce
- * the total number of clip rectangles.
- */
-void GfxSurface::mergeDirtyRects() {
- if (_dirtyRects.size() <= 1)
- return;
-
- Common::List<Rect>::iterator rOuter, rInner;
-
- for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
- rInner = rOuter;
- while (++rInner != _dirtyRects.end()) {
-
- if ((*rOuter).intersects(*rInner)) {
- // these two rectangles overlap or
- // are next to each other - merge them
-
- unionRectangle(*rOuter, *rOuter, *rInner);
-
- // remove the inner rect from the list
- _dirtyRects.erase(rInner);
-
- // move back to beginning of list
- rInner = rOuter;
- }
- }
- }
-}
-
-/**
- * Creates the union of two rectangles.
- * Returns True if there is a union.
- * @param pDest destination rectangle that is to receive the new union
- * @param pSrc1 a source rectangle
- * @param pSrc2 a source rectangle
- */
-bool GfxSurface::unionRectangle(Common::Rect &destRect, const Rect &src1, const Rect &src2) {
- destRect = src1;
- destRect.extend(src2);
-
- return !destRect.isEmpty();
-}
-
/*--------------------------------------------------------------------------*/
GfxElement::GfxElement() {
@@ -762,17 +614,16 @@ void GfxElement::highlight() {
Rect tempRect(_bounds);
tempRect.collapse(g_globals->_gfxEdgeAdjust - 1, g_globals->_gfxEdgeAdjust - 1);
- for (int yp = tempRect.top; yp < tempRect.bottom; ++yp) {
- byte *lineP = (byte *)surface.getBasePtr(tempRect.left, yp);
- for (int xp = tempRect.left; xp < tempRect.right; ++xp, ++lineP) {
+ Graphics::Surface dest = surface.getSubArea(tempRect);
+
+ for (int yp = 0; yp < dest.h; ++yp) {
+ byte *lineP = (byte *)dest.getBasePtr(0, yp);
+ for (int xp = 0; xp < tempRect.right; ++xp, ++lineP) {
if (*lineP == _colors.background) *lineP = _colors.foreground;
else if (*lineP == _colors.foreground) *lineP = _colors.background;
}
}
- // Mark the affected area as dirty
- gfxManager.getSurface().addDirtyRect(tempRect);
-
// Release the surface
gfxManager.unlockSurface();
}
@@ -816,10 +667,11 @@ void GfxElement::drawFrame() {
// Loop through the surface area to replace each pixel
// with its proper shaded replacement
- Graphics::Surface surface = gfxManager.lockSurface();
- for (int y = tempRect.top; y < tempRect.bottom; ++y) {
- byte *lineP = (byte *)surface.getBasePtr(tempRect.left, y);
- for (int x = 0; x < tempRect.width(); ++x) {
+ Graphics::Surface dest = gfxManager.getSurface().getSubArea(tempRect);
+
+ for (int y = 0; y < dest.h; ++y) {
+ byte *lineP = (byte *)dest.getBasePtr(0, y);
+ for (int x = 0; x < dest.w; ++x) {
*lineP = transList[*lineP];
lineP++;
}
@@ -827,27 +679,24 @@ void GfxElement::drawFrame() {
// Draw the edge frame
// Outer frame border
- surface.hLine(tempRect.left + 2, tempRect.top, tempRect.right - 2, 0);
- surface.hLine(tempRect.left + 2, tempRect.bottom, tempRect.right - 2, 0);
- surface.vLine(tempRect.left, tempRect.top + 2, tempRect.bottom - 2, 0);
- surface.vLine(tempRect.right, tempRect.top + 2, tempRect.bottom - 2, 0);
- *((byte *)surface.getBasePtr(tempRect.left + 1, tempRect.top + 1)) = 0;
- *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.top + 1)) = 0;
- *((byte *)surface.getBasePtr(tempRect.left + 1, tempRect.bottom - 1)) = 0;
- *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.bottom - 1)) = 0;
+ dest.hLine(2, 0, dest.w - 2, 0);
+ dest.hLine(2, dest.h - 1, dest.w - 2, 0);
+ dest.vLine(0, 2, dest.h - 2, 0);
+ dest.vLine(tempRect.right, 2, dest.h - 2, 0);
+ *((byte *)dest.getBasePtr(1, 1)) = 0;
+ *((byte *)dest.getBasePtr(dest.w - 1, 1)) = 0;
+ *((byte *)dest.getBasePtr(1, dest.h - 1)) = 0;
+ *((byte *)dest.getBasePtr(dest.w - 1, dest.h - 1)) = 0;
// Inner frame border
- surface.hLine(tempRect.left + 2, tempRect.top + 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColor);
- surface.hLine(tempRect.left + 2, tempRect.bottom - 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColor);
- surface.vLine(tempRect.left + 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColor);
- surface.vLine(tempRect.right - 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColor);
- *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColor;
- *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColor;
- *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColor;
- *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColor;
-
- gfxManager.unlockSurface();
- gfxManager.getSurface().addDirtyRect(tempRect);
+ dest.hLine(2, 1, dest.w - 2, R2_GLOBALS._frameEdgeColor);
+ dest.hLine(2, dest.h - 1, dest.w - 2, R2_GLOBALS._frameEdgeColor);
+ dest.vLine(1, 2, dest.h - 2, R2_GLOBALS._frameEdgeColor);
+ dest.vLine(dest.w - 1, 2, dest.h - 2, R2_GLOBALS._frameEdgeColor);
+ *((byte *)dest.getBasePtr(2, 2)) = R2_GLOBALS._frameEdgeColor;
+ *((byte *)dest.getBasePtr(dest.w - 2, 2)) = R2_GLOBALS._frameEdgeColor;
+ *((byte *)dest.getBasePtr(2, dest.h - 2)) = R2_GLOBALS._frameEdgeColor;
+ *((byte *)dest.getBasePtr(dest.w - 2, dest.h - 2)) = R2_GLOBALS._frameEdgeColor;
} else {
// Fill dialog content with specified background color
@@ -1236,7 +1085,7 @@ GfxButton *GfxDialog::execute(GfxButton *defaultButton) {
}
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
_gfxManager.deactivate();
@@ -1269,7 +1118,7 @@ void GfxDialog::setPalette() {
/*--------------------------------------------------------------------------*/
-GfxManager::GfxManager() : _surface(g_globals->_screenSurface), _oldManager(NULL) {
+GfxManager::GfxManager() : _surface(g_globals->_screen), _oldManager(NULL) {
_font.setOwner(this);
_font._fillFlag = false;
_bounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
@@ -1563,23 +1412,24 @@ int GfxFont::writeChar(const char ch) {
int yOffset = (_fontData[charOffset + 1] >> 3) & 0x1f;
const uint8 *dataP = &_fontData[charOffset + 2];
- // Lock the surface for access
- Graphics::Surface surfacePtr = _gfxManager->lockSurface();
-
Rect charRect;
charRect.set(0, 0, charWidth, _fontSize.y);
charRect.translate(_topLeft.x + _position.x, _topLeft.y + _position.y + yOffset);
+ // Get the sub-section of the screen to update
+ Graphics::Surface dest = _gfxManager->getSurface().getSubArea(charRect);
+
if (_fillFlag)
- surfacePtr.fillRect(charRect, _colors.background);
+ dest.fillRect(charRect, _colors.background);
charRect.bottom = charRect.top + charHeight;
+ assert(charRect.height() <= dest.h);
// Display the character
int bitCtr = 0;
uint8 v = 0;
- for (int yp = charRect.top; yp < charRect.bottom; ++yp) {
- byte *destP = (byte *)surfacePtr.getBasePtr(charRect.left, yp);
+ for (int yp = 0; yp < charHeight; ++yp) {
+ byte *destP = (byte *)dest.getBasePtr(0, yp);
for (int xs = 0; xs < charRect.width(); ++xs, ++destP) {
// Get the next color index to use
@@ -1599,13 +1449,9 @@ int GfxFont::writeChar(const char ch) {
}
}
- // Mark the affected area as dirty
- _gfxManager->getSurface().addDirtyRect(charRect);
-
// Move the text writing position
_position.x += charWidth;
- _gfxManager->unlockSurface();
return charWidth;
}
diff --git a/engines/tsage/graphics.h b/engines/tsage/graphics.h
index 25f7aea8cd..51636c4119 100644
--- a/engines/tsage/graphics.h
+++ b/engines/tsage/graphics.h
@@ -28,7 +28,7 @@
#include "common/list.h"
#include "common/rect.h"
#include "common/system.h"
-#include "graphics/surface.h"
+#include "graphics/screen.h"
namespace TsAGE {
@@ -73,20 +73,23 @@ public:
enum FrameFlag { FRAME_FLIP_CENTROID_X = 4, FRAME_FLIP_CENTROID_Y = 8 };
-class GfxSurface {
+/**
+ * Surface class. This derivces from Graphics::Screen because it has
+ * logic we'll need for our own Screen class that derives from this one
+ */
+ class GfxSurface: public Graphics::Screen {
private:
- Graphics::Surface *_customSurface;
int _lockSurfaceCtr;
+ Graphics::ManagedSurface _rawSurface;
bool _disableUpdates;
Rect _bounds;
-
- bool _trackDirtyRects;
- Common::List<Rect> _dirtyRects;
-
- void mergeDirtyRects();
- bool unionRectangle(Common::Rect &destRect, const Rect &src1, const Rect &src2);
-
+ protected:
+ /**
+ * Override the addDirtyRect from Graphics::Screen, since for standard
+ * surfaces we don't need dirty rects to be tracked
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {}
public:
Common::Point _centroid;
int _transColor;
@@ -95,17 +98,13 @@ public:
public:
GfxSurface();
GfxSurface(const GfxSurface &s);
- ~GfxSurface();
+ virtual ~GfxSurface();
- void setScreenSurface();
- void updateScreen();
- void addDirtyRect(const Rect &r);
- Graphics::Surface lockSurface();
+ Graphics::ManagedSurface &lockSurface();
void unlockSurface();
void synchronize(Serializer &s);
- void create(int width, int height);
- void clear();
- void setBounds(const Rect &bounds) { _bounds = bounds; }
+ virtual void create(uint16 width, uint16 height);
+ void setBounds(const Rect &bounds);
const Rect &getBounds() const { return _bounds; }
void copyFrom(GfxSurface &src, Rect srcBounds, Rect destBounds,
@@ -119,10 +118,9 @@ public:
copyFrom(src, tempRect, priorityRegion);
}
void draw(const Common::Point &pt, Rect *rect = NULL);
- void fillRect(const Rect &bounds, int color);
GfxSurface &operator=(const GfxSurface &s);
- static void loadScreenSection(Graphics::Surface &dest, int xHalf, int yHalf, int xSection, int ySection);
+ static void loadScreenSection(Graphics::ManagedSurface &dest, int xHalf, int yHalf, int xSection, int ySection);
static bool displayText(const Common::String &msg, const Common::Point &pt = Common::Point(160, 100));
};
@@ -281,7 +279,7 @@ public:
void getStringBounds(const char *s, Rect &bounds, int maxWidth);
void setDialogPalette();
- Graphics::Surface lockSurface() {
+ Graphics::ManagedSurface lockSurface() {
_surface.setBounds(_bounds);
return _surface.lockSurface();
}
diff --git a/engines/tsage/module.mk b/engines/tsage/module.mk
index e23b157a95..b58c748567 100644
--- a/engines/tsage/module.mk
+++ b/engines/tsage/module.mk
@@ -47,6 +47,7 @@ MODULE_OBJS := \
ringworld2/ringworld2_vampire.o \
saveload.o \
scenes.o \
+ screen.o \
sherlock/sherlock_logo.o \
sound.o \
staticres.o \
diff --git a/engines/tsage/ringworld/ringworld_demo.cpp b/engines/tsage/ringworld/ringworld_demo.cpp
index cd2ab07a50..9aab0c4d21 100644
--- a/engines/tsage/ringworld/ringworld_demo.cpp
+++ b/engines/tsage/ringworld/ringworld_demo.cpp
@@ -21,6 +21,7 @@
*/
#include "tsage/ringworld/ringworld_demo.h"
+#include "tsage/dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
@@ -79,11 +80,7 @@ void RingworldDemoGame::processEvent(Event &event) {
case Common::KEYCODE_F2: {
// F2 - Sound Options
- ConfigDialog *dlg = new ConfigDialog();
- dlg->runModal();
- delete dlg;
- g_globals->_soundManager.syncSounds();
- g_globals->_events.setCursorFromFlag();
+ SoundDialog::execute();
break;
}
diff --git a/engines/tsage/ringworld/ringworld_dialogs.cpp b/engines/tsage/ringworld/ringworld_dialogs.cpp
index 1dd3bc158b..bc357cac25 100644
--- a/engines/tsage/ringworld/ringworld_dialogs.cpp
+++ b/engines/tsage/ringworld/ringworld_dialogs.cpp
@@ -20,9 +20,6 @@
*
*/
-#include "gui/dialog.h"
-#include "gui/widget.h"
-
#include "tsage/tsage.h"
#include "tsage/core.h"
#include "tsage/dialogs.h"
@@ -181,7 +178,7 @@ void RightClickDialog::execute() {
}
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
_gfxManager.deactivate();
@@ -391,7 +388,7 @@ void InventoryDialog::execute() {
Event event;
while (!g_globals->_events.getEvent(event) && !g_vm->shouldQuit()) {
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
if (g_vm->shouldQuit())
break;
@@ -439,7 +436,7 @@ void InventoryDialog::execute() {
// Inventory item selected
InvObject *invObject = static_cast<GfxInvImage *>(hiliteObj)->_invObject;
if (lookFlag) {
- g_globals->_screenSurface.displayText(invObject->_description);
+ g_globals->_screen.displayText(invObject->_description);
} else {
RING_INVENTORY._selectedItem = invObject;
invObject->setCursor();
diff --git a/engines/tsage/ringworld/ringworld_dialogs.h b/engines/tsage/ringworld/ringworld_dialogs.h
index 68ac0a05f9..4753968bf3 100644
--- a/engines/tsage/ringworld/ringworld_dialogs.h
+++ b/engines/tsage/ringworld/ringworld_dialogs.h
@@ -23,7 +23,7 @@
#ifndef TSAGE_RINGWORLD_DIALOGS_H
#define TSAGE_RINGWORLD_DIALOGS_H
-#include "gui/options.h"
+#include "tsage/dialogs.h"
#include "tsage/events.h"
#include "tsage/graphics.h"
#include "common/list.h"
diff --git a/engines/tsage/ringworld/ringworld_logic.cpp b/engines/tsage/ringworld/ringworld_logic.cpp
index 1d8293cffd..354c86abfc 100644
--- a/engines/tsage/ringworld/ringworld_logic.cpp
+++ b/engines/tsage/ringworld/ringworld_logic.cpp
@@ -320,7 +320,7 @@ void SceneArea::wait() {
// Wait until a mouse or keypress
Event event;
while (!g_vm->shouldQuit() && !g_globals->_events.getEvent(event)) {
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
}
diff --git a/engines/tsage/ringworld/ringworld_scenes2.cpp b/engines/tsage/ringworld/ringworld_scenes2.cpp
index 1140f6f3d1..6811d3c3e8 100644
--- a/engines/tsage/ringworld/ringworld_scenes2.cpp
+++ b/engines/tsage/ringworld/ringworld_scenes2.cpp
@@ -22,6 +22,7 @@
#include "common/config-manager.h"
#include "tsage/ringworld/ringworld_scenes2.h"
+#include "tsage/dialogs.h"
#include "tsage/scenes.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
diff --git a/engines/tsage/ringworld/ringworld_scenes3.cpp b/engines/tsage/ringworld/ringworld_scenes3.cpp
index a515224964..a9ed7af870 100644
--- a/engines/tsage/ringworld/ringworld_scenes3.cpp
+++ b/engines/tsage/ringworld/ringworld_scenes3.cpp
@@ -532,7 +532,7 @@ void Scene2100::Action1::signal() {
// Wait for an event
Event event;
if (!g_globals->_events.getEvent(event)) {
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
continue;
}
@@ -2265,7 +2265,7 @@ void Scene2150::Action1::signal() {
// Wait for an event
Event event;
if (!g_globals->_events.getEvent(event)) {
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
continue;
}
@@ -5119,7 +5119,7 @@ void Scene2320::Action3::signal() {
// Wait for an event
Event event;
if (!g_globals->_events.getEvent(event)) {
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
continue;
}
diff --git a/engines/tsage/ringworld/ringworld_scenes5.cpp b/engines/tsage/ringworld/ringworld_scenes5.cpp
index cb8a89de80..98859f32ee 100644
--- a/engines/tsage/ringworld/ringworld_scenes5.cpp
+++ b/engines/tsage/ringworld/ringworld_scenes5.cpp
@@ -2813,7 +2813,7 @@ void Scene4150::Action1::signal() {
case 4: {
for (int idx = 100; idx >= 0; idx -= 5) {
g_globals->_scenePalette.fade(adjustData, false, idx);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
}
@@ -2841,7 +2841,7 @@ void Scene4150::Action1::signal() {
case 7:
for (int idx = 100; idx >= 0; idx -= 5) {
g_globals->_scenePalette.fade(adjustData, false, idx);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
}
diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp
index 99f88a1687..5cd124f91d 100644
--- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp
+++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp
@@ -22,9 +22,6 @@
#include "common/translation.h"
-#include "gui/dialog.h"
-#include "gui/widget.h"
-
#include "tsage/tsage.h"
#include "tsage/core.h"
#include "tsage/dialogs.h"
@@ -154,7 +151,7 @@ int RightClickDialog::execute() {
}
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
// Execute the specified action
diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.h b/engines/tsage/ringworld2/ringworld2_dialogs.h
index 3d1e1ad48c..71e0c23f35 100644
--- a/engines/tsage/ringworld2/ringworld2_dialogs.h
+++ b/engines/tsage/ringworld2/ringworld2_dialogs.h
@@ -23,7 +23,7 @@
#ifndef TSAGE_RINGWORLD2_DIALOGS_H
#define TSAGE_RINGWORLD2_DIALOGS_H
-#include "gui/options.h"
+#include "tsage/core.h"
#include "tsage/dialogs.h"
#include "tsage/events.h"
#include "tsage/graphics.h"
diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp
index d24541932f..ecaa671bd7 100644
--- a/engines/tsage/ringworld2/ringworld2_logic.cpp
+++ b/engines/tsage/ringworld2/ringworld2_logic.cpp
@@ -351,7 +351,7 @@ SceneExt::SceneExt(): Scene() {
_preventSaving = false;
// Reset screen clipping area
- R2_GLOBALS._screenSurface._clipRect = Rect();
+ R2_GLOBALS._screen._clipRect = Rect();
// WORKAROUND: In the original, playing animations don't reset the global _animationCtr
// counter as scene changes unless the playing animation explicitly finishes. For now,
@@ -513,7 +513,7 @@ void SceneExt::endStrip() {
}
void SceneExt::clearScreen() {
- R2_GLOBALS._screenSurface.fillRect(R2_GLOBALS._screenSurface.getBounds(), 0);
+ R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0);
}
void SceneExt::refreshBackground(int xAmount, int yAmount) {
@@ -543,15 +543,12 @@ void SceneExt::refreshBackground(int xAmount, int yAmount) {
int screenSize = g_vm->_memoryManager.getSize(dataP);
// Lock the background for update
- Graphics::Surface s = _backSurface.lockSurface();
- assert(screenSize == (s.w * s.h));
+ assert(screenSize == (_backSurface.w * _backSurface.h));
+ Graphics::Surface s = _backSurface.getSubArea(Common::Rect(0, 0, _backSurface.w, _backSurface.h));
- // Copy the data
+ // Copy the data into the surface
byte *destP = (byte *)s.getPixels();
Common::copy(dataP, dataP + (s.w * s.h), destP);
- _backSurface.unlockSurface();
-
- R2_GLOBALS._screenSurface.addDirtyRect(_backSurface.getBounds());
// Free the resource data
DEALLOCATE(dataP);
@@ -601,7 +598,7 @@ void SceneExt::loadBlankScene() {
_backSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT * 3 / 2);
_backSurface.fillRect(_backSurface.getBounds(), 0);
- R2_GLOBALS._screenSurface.fillRect(R2_GLOBALS._screenSurface.getBounds(), 0);
+ R2_GLOBALS._screen.fillRect(R2_GLOBALS._screen.getBounds(), 0);
}
/*--------------------------------------------------------------------------*/
@@ -1966,10 +1963,9 @@ void AnimationPlayer::drawFrame(int sliceIndex) {
byte *sliceData1 = sliceDataStart;
Rect playerBounds = _screenBounds;
- int y = _screenBounds.top;
- R2_GLOBALS._screenSurface.addDirtyRect(playerBounds);
- Graphics::Surface surface = R2_GLOBALS._screenSurface.lockSurface();
+ Graphics::Surface dest = R2_GLOBALS._screen.getSubArea(playerBounds);
+ int y = 0;
// Handle different drawing modes
switch (slice._drawMode) {
@@ -1980,7 +1976,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) {
// TODO: Check of _subData._drawType was done for two different kinds of
// line slice drawing in original
const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
- byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, y++);
+ byte *pDest = (byte *)dest.getBasePtr(0, y++);
Common::copy(pSrc, pSrc + _subData._sliceSize, pDest);
}
@@ -1997,7 +1993,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) {
if (offset) {
const byte *pSrc = (const byte *)sliceDataStart + offset;
- byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, playerBounds.top);
+ byte *pDest = (byte *)dest.getBasePtr(0, 0);
//Common::copy(pSrc, pSrc + playerBounds.width(), pDest);
rleDecode(pSrc, pDest, playerBounds.width());
@@ -2012,7 +2008,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) {
// TODO: Check of _subData._drawType was done for two different kinds of
// line slice drawing in original
const byte *pSrc = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
- byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, playerBounds.top);
+ byte *pDest = (byte *)dest.getBasePtr(0, 0);
rleDecode(pSrc, pDest, _subData._sliceSize);
}
@@ -2027,7 +2023,7 @@ void AnimationPlayer::drawFrame(int sliceIndex) {
for (int yIndex = 0; yIndex < _sliceHeight; ++yIndex) {
const byte *pSrc1 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData2 + sliceNum * 2);
const byte *pSrc2 = (const byte *)sliceDataStart + READ_LE_UINT16(sliceData1 + sliceNum * 2);
- byte *pDest = (byte *)surface.getBasePtr(playerBounds.left, y++);
+ byte *pDest = (byte *)dest.getBasePtr(0, y++);
if (slice2._drawMode == 0) {
// Uncompressed background, foreground compressed
@@ -2047,17 +2043,14 @@ void AnimationPlayer::drawFrame(int sliceIndex) {
break;
}
- // Unlock the screen surface
- R2_GLOBALS._screenSurface.unlockSurface();
-
if (_objectMode == ANIMOBJMODE_42) {
_screenBounds.expandPanes();
// Copy the drawn frame to the back surface
- Rect srcRect = R2_GLOBALS._screenSurface.getBounds();
+ Rect srcRect = R2_GLOBALS._screen.getBounds();
Rect destRect = srcRect;
destRect.translate(-g_globals->_sceneOffset.x, -g_globals->_sceneOffset.y);
- R2_GLOBALS._sceneManager._scene->_backSurface.copyFrom(R2_GLOBALS._screenSurface,
+ R2_GLOBALS._sceneManager._scene->_backSurface.copyFrom(R2_GLOBALS._screen,
srcRect, destRect);
// Draw any objects into the scene
diff --git a/engines/tsage/ringworld2/ringworld2_outpost.cpp b/engines/tsage/ringworld2/ringworld2_outpost.cpp
index cad21b4623..d0d67031ec 100644
--- a/engines/tsage/ringworld2/ringworld2_outpost.cpp
+++ b/engines/tsage/ringworld2/ringworld2_outpost.cpp
@@ -21,6 +21,7 @@
*/
#include "graphics/cursorman.h"
+#include "tsage/dialogs.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
#include "tsage/ringworld2/ringworld2_outpost.h"
@@ -4689,7 +4690,7 @@ GfxButton *Scene1337::OptionsDialog::execute(GfxButton *defaultButton) {
}
g_system->delayMillis(10);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
}
_gfxManager.deactivate();
diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp
index 573cbbb29a..63879b0366 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp
@@ -1613,7 +1613,7 @@ void Scene180::signal() {
case 43:
case 47:
_helpEnabled = false;
- R2_GLOBALS._screenSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ R2_GLOBALS._screen.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
_palette.loadPalette(0);
_palette.loadPalette(9998);
R2_GLOBALS._scenePalette.addFader(_palette._palette, 256, 8, this);
@@ -1815,7 +1815,7 @@ void Scene180::signal() {
_shipDisplay.remove();
_backSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- R2_GLOBALS._screenSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ R2_GLOBALS._screen.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
R2_GLOBALS._sound2.fadeOut2(NULL);
R2_GLOBALS._sound1.fadeOut2(this);
break;
@@ -1880,7 +1880,7 @@ void Scene180::signal() {
R2_GLOBALS._paneRefreshFlag[0] = 3;
_backSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
- R2_GLOBALS._screenSurface.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ R2_GLOBALS._screen.fillRect(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
setSceneDelay(1);
break;
diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
index 81dc05e2a4..70937fcbc4 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp
@@ -23,6 +23,7 @@
#include "graphics/cursorman.h"
#include "tsage/scenes.h"
+#include "tsage/dialogs.h"
#include "tsage/tsage.h"
#include "tsage/staticres.h"
#include "tsage/ringworld2/ringworld2_scenes1.h"
diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp
index bd8a0cdd0d..6b44ecc514 100644
--- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp
+++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp
@@ -1440,7 +1440,7 @@ void Scene2425::postInit(SceneObjectList *OwnerList) {
case 2425:
_sceneMode = 10;
R2_GLOBALS._player.setPosition(Common::Point(280, 150));
- _action->signal();
+ signal();
break;
case 2455:
_sceneMode = 2428;
diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp
index 9954b929b2..3cb8e52692 100644
--- a/engines/tsage/saveload.cpp
+++ b/engines/tsage/saveload.cpp
@@ -289,10 +289,10 @@ void Saver::writeSavegameHeader(Common::OutSaveFile *out, tSageSavegameHeader &h
// Create a thumbnail and save it
Graphics::Surface *thumb = new Graphics::Surface();
- Graphics::Surface s = g_globals->_screenSurface.lockSurface();
+ Graphics::Surface s = g_globals->_screen.lockSurface();
::createThumbnail(thumb, (const byte *)s.getPixels(), SCREEN_WIDTH, SCREEN_HEIGHT, thumbPalette);
Graphics::saveThumbnail(*out, *thumb);
- g_globals->_screenSurface.unlockSurface();
+ g_globals->_screen.unlockSurface();
thumb->free();
delete thumb;
diff --git a/engines/tsage/scenes.cpp b/engines/tsage/scenes.cpp
index 80ce1e3ecc..6f2f953aee 100644
--- a/engines/tsage/scenes.cpp
+++ b/engines/tsage/scenes.cpp
@@ -23,6 +23,7 @@
#include "common/config-manager.h"
#include "common/translation.h"
#include "gui/saveload.h"
+#include "tsage/dialogs.h"
#include "tsage/scenes.h"
#include "tsage/globals.h"
#include "tsage/ringworld/ringworld_logic.h"
@@ -139,7 +140,7 @@ void SceneManager::fadeInIfNecessary() {
percent = 100;
g_globals->_scenePalette.fade((const byte *)&adjustData, false, percent);
- GLOBALS._screenSurface.updateScreen();
+ GLOBALS._screen.update();
g_system->delayMillis(10);
}
@@ -175,7 +176,7 @@ void SceneManager::changeScene(int newSceneNumber) {
}
// Blank out the screen
- g_globals->_screenSurface.fillRect(g_globals->_screenSurface.getBounds(), 0);
+ g_globals->_screen.fillRect(g_globals->_screen.getBounds(), 0);
// If there are any fading sounds, wait until fading is complete
while (g_globals->_soundManager.isFading()) {
@@ -463,7 +464,7 @@ void Scene::refreshBackground(int xAmount, int yAmount) {
// Check if the section is already loaded
if ((_enabledSections[xp * 16 + yp] == 0xffff) || ((xAmount == 0) && (yAmount == 0))) {
// Chunk isn't loaded, so load it in
- Graphics::Surface s = _backSurface.lockSurface();
+ Graphics::ManagedSurface s = _backSurface.lockSurface();
GfxSurface::loadScreenSection(s, xp - xHalfOffset, yp - yHalfOffset, xp, yp);
_backSurface.unlockSurface();
changedFlag = true;
diff --git a/engines/tsage/screen.cpp b/engines/tsage/screen.cpp
new file mode 100644
index 0000000000..eaf2067c32
--- /dev/null
+++ b/engines/tsage/screen.cpp
@@ -0,0 +1,51 @@
+/* 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.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "tsage/screen.h"
+
+namespace TsAGE {
+
+Screen::Screen(): GfxSurface() {
+ create(SCREEN_WIDTH, SCREEN_HEIGHT);
+}
+
+Screen::~Screen() {
+ // Delete the screen's surface
+ free();
+}
+
+void Screen::update() {
+ // When dialogs are active, the screen surface may be remapped to
+ // sub-sections of the screen. But for drawing we'll need to temporarily
+ // remove any such remappings and use the entirety of the screen
+ Rect clipBounds = getBounds();
+ setBounds(Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+ // Update the screen
+ Graphics::Screen::update();
+
+ // Reset the clipping
+ setBounds(clipBounds);
+}
+
+} // End of namespace TsAGE
diff --git a/engines/tsage/screen.h b/engines/tsage/screen.h
new file mode 100644
index 0000000000..c5cfee754a
--- /dev/null
+++ b/engines/tsage/screen.h
@@ -0,0 +1,66 @@
+/* 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.
+ *
+ */
+
+#ifndef TSAGE_SCREEN_H
+#define TSAGE_SCREEN_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+#include "graphics/screen.h"
+#include "tsage/graphics.h"
+
+namespace TsAGE {
+
+#define SCREEN_WIDTH 320
+#define SCREEN_HEIGHT 200
+#define SCREEN_CENTER_X 160
+#define SCREEN_CENTER_Y 100
+#define UI_INTERFACE_Y 168
+
+class Screen : public GfxSurface {
+ /**
+ * Override the addDirtyRect from GfxSurface, since for our screen
+ * class we need to reintroduce the standard Graphics::Screen implementation
+ */
+ virtual void addDirtyRect(const Common::Rect &r) {
+ Graphics::Screen::addDirtyRect(r);
+ }
+public:
+ /**
+ * Constructor
+ */
+ Screen();
+
+ /**
+ * Destructor
+ */
+ virtual ~Screen();
+
+ /**
+ * Update the screen
+ */
+ virtual void update();
+};
+
+} // End of namespace TsAGE
+
+#endif /* MADS_SCREEN_H */
diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h
index 68755a48c8..da56c8bfa5 100644
--- a/engines/tsage/sound.h
+++ b/engines/tsage/sound.h
@@ -26,12 +26,15 @@
#include "common/scummsys.h"
#include "common/mutex.h"
#include "common/queue.h"
-#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/list.h"
#include "tsage/saveload.h"
#include "tsage/core.h"
+namespace Audio {
+class QueuingAudioStream;
+}
+
namespace OPL {
class OPL;
}
diff --git a/engines/tsage/tsage.h b/engines/tsage/tsage.h
index 667a8daa59..ca29d68243 100644
--- a/engines/tsage/tsage.h
+++ b/engines/tsage/tsage.h
@@ -20,13 +20,10 @@
*
*/
-#ifndef TSAGE_H
-#define TSAGE_H
+#ifndef TSAGE_TSAGE_H
+#define TSAGE_TSAGE_H
#include "engines/engine.h"
-#include "common/rect.h"
-#include "audio/mixer.h"
-#include "common/file.h"
#include "gui/debugger.h"
#include "tsage/core.h"
@@ -62,12 +59,6 @@ enum {
struct tSageGameDescription;
-#define SCREEN_WIDTH 320
-#define SCREEN_HEIGHT 200
-#define SCREEN_CENTER_X 160
-#define SCREEN_CENTER_Y 100
-#define UI_INTERFACE_Y 168
-
class TSageEngine : public Engine {
private:
const tSageGameDescription *_gameDescription;
diff --git a/engines/tsage/user_interface.cpp b/engines/tsage/user_interface.cpp
index 3ee585d5ef..fffc0dc16c 100644
--- a/engines/tsage/user_interface.cpp
+++ b/engines/tsage/user_interface.cpp
@@ -253,7 +253,7 @@ void UICollection::show() {
void UICollection::erase() {
if (_clearScreen) {
Rect tempRect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT);
- GLOBALS._screenSurface.fillRect(tempRect, 0);
+ GLOBALS._screen.fillRect(tempRect, 0);
GLOBALS._sceneManager._scene->_backSurface.fillRect(tempRect, 0);
_clearScreen = false;
}
@@ -274,7 +274,7 @@ void UICollection::draw() {
_objList[idx]->draw();
// Draw the resulting UI onto the screen
- GLOBALS._screenSurface.copyFrom(GLOBALS._sceneManager._scene->_backSurface,
+ GLOBALS._screen.copyFrom(GLOBALS._sceneManager._scene->_backSurface,
Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT),
Rect(0, UI_INTERFACE_Y, SCREEN_WIDTH, SCREEN_HEIGHT));
@@ -293,12 +293,12 @@ void UICollection::r2rDrawFrame() {
GfxSurface vertLineRight = visage.getFrame(3);
GfxSurface horizLine = visage.getFrame(2);
- GLOBALS._screenSurface.copyFrom(horizLine, 0, 0);
- GLOBALS._screenSurface.copyFrom(vertLineLeft, 0, 3);
- GLOBALS._screenSurface.copyFrom(vertLineRight, SCREEN_WIDTH - 4, 3);
+ GLOBALS._screen.copyFrom(horizLine, 0, 0);
+ GLOBALS._screen.copyFrom(vertLineLeft, 0, 3);
+ GLOBALS._screen.copyFrom(vertLineRight, SCREEN_WIDTH - 4, 3);
// Restrict drawing area to exclude the borders at the edge of the screen
- R2_GLOBALS._screenSurface._clipRect = Rect(4, 3, SCREEN_WIDTH - 4,
+ R2_GLOBALS._screen._clipRect = Rect(4, 3, SCREEN_WIDTH - 4,
SCREEN_HEIGHT - 3);
}
diff --git a/engines/tucker/detection.cpp b/engines/tucker/detection.cpp
index a2878f4cc8..2447e15d6b 100644
--- a/engines/tucker/detection.cpp
+++ b/engines/tucker/detection.cpp
@@ -116,7 +116,7 @@ class TuckerMetaEngine : public AdvancedMetaEngine {
public:
TuckerMetaEngine() : AdvancedMetaEngine(tuckerGameDescriptions, sizeof(ADGameDescription), tuckerGames) {
_md5Bytes = 512;
- _singleid = "tucker";
+ _singleId = "tucker";
}
virtual const char *getName() const {
diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp
index 9cba7b523d..d7b75e39c1 100644
--- a/engines/tucker/resource.cpp
+++ b/engines/tucker/resource.cpp
@@ -662,9 +662,11 @@ void TuckerEngine::loadData3() {
void TuckerEngine::loadData4() {
loadFile("data4.c", _loadTempBuf);
DataTokenizer t(_loadTempBuf, _fileLoadSize);
- t.findNextToken(kDataTokenDw);
- _gameDebug = t.getNextInteger() != 0;
- _displayGameHints = t.getNextInteger() != 0;
+ if ((_gameFlags & kGameFlagDemo) == 0) {
+ t.findNextToken(kDataTokenDw);
+ _gameDebug = t.getNextInteger() != 0;
+ _displayGameHints = t.getNextInteger() != 0;
+ }
_locationObjectsCount = 0;
if (t.findIndex(_locationNum)) {
while (t.findNextToken(kDataTokenDw)) {
diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h
index 2ab94dedbc..1be4682508 100644
--- a/engines/tucker/tucker.h
+++ b/engines/tucker/tucker.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef TUCKER_ENGINE_H
-#define TUCKER_ENGINE_H
+#ifndef TUCKER_TUCKER_H
+#define TUCKER_TUCKER_H
#include "common/file.h"
#include "common/util.h"
diff --git a/engines/voyeur/animation.cpp b/engines/voyeur/animation.cpp
index 62b37346da..d5d58a2fd3 100644
--- a/engines/voyeur/animation.cpp
+++ b/engines/voyeur/animation.cpp
@@ -470,7 +470,7 @@ void RL2Decoder::play(VoyeurEngine *vm, int resourceOffset,
if (hasDirtyPalette()) {
const byte *palette = getPalette();
- vm->_graphicsManager->setPalette128(palette, paletteStart, paletteCount);
+ vm->_screen->setPalette128(palette, paletteStart, paletteCount);
}
if (needsUpdate()) {
@@ -482,15 +482,14 @@ void RL2Decoder::play(VoyeurEngine *vm, int resourceOffset,
Common::Point pt(READ_LE_UINT16(imgPos + 4 * picCtr) - 32,
READ_LE_UINT16(imgPos + 4 * picCtr + 2) - 20);
- vm->_graphicsManager->sDrawPic(newPic, &videoFrame, pt);
+ vm->_screen->sDrawPic(newPic, &videoFrame, pt);
++picCtr;
}
}
// Decode the next frame and display
const Graphics::Surface *frame = decodeNextFrame();
- Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200,
- (byte *)vm->_graphicsManager->_screenSurface.getPixels());
+ vm->_screen->blitFrom(*frame);
}
vm->_eventsManager->getMouseInfo();
diff --git a/engines/voyeur/animation.h b/engines/voyeur/animation.h
index bc6d8a361a..c20ccf7284 100644
--- a/engines/voyeur/animation.h
+++ b/engines/voyeur/animation.h
@@ -26,13 +26,16 @@
#include "video/video_decoder.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
-#include "audio/timestamp.h"
#include "common/array.h"
#include "common/list.h"
#include "common/rect.h"
#include "common/stream.h"
#include "voyeur/files.h"
+namespace Audio {
+class Timestamp;
+}
+
namespace Voyeur {
class VoyeurEngine;
diff --git a/engines/voyeur/data.cpp b/engines/voyeur/data.cpp
index b8c987f18b..4d6e32436d 100644
--- a/engines/voyeur/data.cpp
+++ b/engines/voyeur/data.cpp
@@ -240,10 +240,10 @@ void SVoy::reviewAnEvidEvent(int eventIndex) {
int frameOff = e._computerOff;
if (_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)) {
- _vm->_graphicsManager->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource;
- _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource;
- _vm->_graphicsManager->_vPort->setupViewPort(_vm->_graphicsManager->_backgroundPage);
- _vm->_graphicsManager->_backColors->startFade();
+ _vm->_screen->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource;
+ _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource;
+ _vm->_screen->_vPort->setupViewPort(_vm->_screen->_backgroundPage);
+ _vm->_screen->_backColors->startFade();
_vm->doEvidDisplay(frameOff, e._dead);
_vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId);
@@ -262,10 +262,10 @@ void SVoy::reviewComputerEvent(int eventIndex) {
_computerTextId = e._computerOn;
if (_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId)) {
- _vm->_graphicsManager->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource;
- _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource;
- _vm->_graphicsManager->_vPort->setupViewPort(_vm->_graphicsManager->_backgroundPage);
- _vm->_graphicsManager->_backColors->startFade();
+ _vm->_screen->_backColors = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 1)._cMapResource;
+ _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(_vm->_playStampGroupId)._picResource;
+ _vm->_screen->_vPort->setupViewPort(_vm->_screen->_backgroundPage);
+ _vm->_screen->_backColors->startFade();
_vm->flipPageAndWaitForFade();
_vm->getComputerBrush();
diff --git a/engines/voyeur/debugger.cpp b/engines/voyeur/debugger.cpp
index e9a12180da..ebfa123eb6 100644
--- a/engines/voyeur/debugger.cpp
+++ b/engines/voyeur/debugger.cpp
@@ -21,7 +21,7 @@
*/
#include "voyeur/debugger.h"
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
#include "voyeur/voyeur.h"
#include "voyeur/staticres.h"
diff --git a/engines/voyeur/detection.cpp b/engines/voyeur/detection.cpp
index 9e5320aac8..7b9fa6722e 100644
--- a/engines/voyeur/detection.cpp
+++ b/engines/voyeur/detection.cpp
@@ -75,7 +75,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Voyeur (c) Philips P.O.V. Entertainment Group";
+ return "Voyeur (C) Philips P.O.V. Entertainment Group";
}
virtual bool hasFeature(MetaEngineFeature f) const;
diff --git a/engines/voyeur/events.cpp b/engines/voyeur/events.cpp
index 34ef507ad3..020fe4b692 100644
--- a/engines/voyeur/events.cpp
+++ b/engines/voyeur/events.cpp
@@ -111,18 +111,18 @@ void EventsManager::mainVoyeurIntFunc() {
}
void EventsManager::sWaitFlip() {
- Common::Array<ViewPortResource *> &viewPorts = _vm->_graphicsManager->_viewPortListPtr->_entries;
+ Common::Array<ViewPortResource *> &viewPorts = _vm->_screen->_viewPortListPtr->_entries;
for (uint idx = 0; idx < viewPorts.size(); ++idx) {
ViewPortResource &viewPort = *viewPorts[idx];
- if (_vm->_graphicsManager->_saveBack && (viewPort._flags & DISPFLAG_40)) {
- Common::Rect *clipPtr = _vm->_graphicsManager->_clipPtr;
- _vm->_graphicsManager->_clipPtr = &viewPort._clipRect;
+ if (_vm->_screen->_saveBack && (viewPort._flags & DISPFLAG_40)) {
+ Common::Rect *clipPtr = _vm->_screen->_clipPtr;
+ _vm->_screen->_clipPtr = &viewPort._clipRect;
if (viewPort._restoreFn)
- (_vm->_graphicsManager->*viewPort._restoreFn)(&viewPort);
+ (_vm->_screen->*viewPort._restoreFn)(&viewPort);
- _vm->_graphicsManager->_clipPtr = clipPtr;
+ _vm->_screen->_clipPtr = clipPtr;
viewPort._rectListCount[viewPort._pageIndex] = 0;
viewPort._rectListPtr[viewPort._pageIndex]->clear();
viewPort._flags &= ~DISPFLAG_40;
@@ -158,9 +158,7 @@ void EventsManager::checkForNextFrameCounter() {
showMousePosition();
// Display the frame
- g_system->copyRectToScreen((byte *)_vm->_graphicsManager->_screenSurface.getPixels(),
- SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
- g_system->updateScreen();
+ _vm->_screen->update();
// Signal the ScummVM debugger
_vm->_debugger->onFrame();
@@ -178,10 +176,8 @@ void EventsManager::showMousePosition() {
mousePos += Common::String::format(" - (%d,%d)", pt.x, pt.y);
}
- _vm->_graphicsManager->_screenSurface.fillRect(
- Common::Rect(0, 0, 110, font.getFontHeight()), 0);
- font.drawString(&_vm->_graphicsManager->_screenSurface, mousePos,
- 0, 0, 110, 63);
+ _vm->_screen->fillRect(Common::Rect(0, 0, 110, font.getFontHeight()), 0);
+ font.drawString(_vm->_screen, mousePos, 0, 0, 110, 63);
}
void EventsManager::voyeurTimer() {
@@ -299,11 +295,11 @@ void EventsManager::startFade(CMapResource *cMap) {
if (cMap->_steps > 0) {
_fadeStatus = cMap->_fadeStatus | 1;
- byte *vgaP = &_vm->_graphicsManager->_VGAColors[_fadeFirstCol * 3];
+ byte *vgaP = &_vm->_screen->_VGAColors[_fadeFirstCol * 3];
int mapIndex = 0;
for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) {
- ViewPortPalEntry &palEntry = _vm->_graphicsManager->_viewPortListPtr->_palette[idx];
+ ViewPortPalEntry &palEntry = _vm->_screen->_viewPortListPtr->_palette[idx];
palEntry._rEntry = vgaP[0] << 8;
int rDiff = (cMap->_entries[mapIndex * 3] << 8) - palEntry._rEntry;
palEntry._rChange = rDiff / cMap->_steps;
@@ -325,7 +321,7 @@ void EventsManager::startFade(CMapResource *cMap) {
_intPtr._skipFading = true;
_fadeIntNode._flags &= ~1;
} else {
- byte *vgaP = &_vm->_graphicsManager->_VGAColors[_fadeFirstCol * 3];
+ byte *vgaP = &_vm->_screen->_VGAColors[_fadeFirstCol * 3];
int mapIndex = 0;
for (int idx = _fadeFirstCol; idx <= _fadeLastCol; ++idx, vgaP += 3) {
@@ -371,8 +367,8 @@ void EventsManager::vDoFadeInt() {
}
for (int i = _fadeFirstCol; i <= _fadeLastCol; ++i) {
- ViewPortPalEntry &palEntry = _vm->_graphicsManager->_viewPortListPtr->_palette[i];
- byte *vgaP = &_vm->_graphicsManager->_VGAColors[palEntry._palIndex * 3];
+ ViewPortPalEntry &palEntry = _vm->_screen->_viewPortListPtr->_palette[i];
+ byte *vgaP = &_vm->_screen->_VGAColors[palEntry._palIndex * 3];
palEntry._rEntry += palEntry._rChange;
palEntry._gEntry += palEntry._gChange;
@@ -395,7 +391,7 @@ void EventsManager::vDoCycleInt() {
for (int idx = 3; idx >= 0; --idx) {
if (_cyclePtr->_type[idx] && --_cycleTime[idx] <= 0) {
byte *pSrc = _cycleNext[idx];
- byte *pPal = _vm->_graphicsManager->_VGAColors;
+ byte *pPal = _vm->_screen->_VGAColors;
if (_cyclePtr->_type[idx] != 1) {
// New palette data being specified - loop to set entries
@@ -521,7 +517,7 @@ void EventsManager::setCursor(PictureResource *pic) {
cursor._bounds = pic->_bounds;
cursor._flags = DISPFLAG_CURSOR;
- _vm->_graphicsManager->sDrawPic(pic, &cursor, Common::Point());
+ _vm->_screen->sDrawPic(pic, &cursor, Common::Point());
}
void EventsManager::setCursor(byte *cursorData, int width, int height, int keyColor) {
@@ -531,16 +527,16 @@ void EventsManager::setCursor(byte *cursorData, int width, int height, int keyCo
void EventsManager::setCursorColor(int idx, int mode) {
switch (mode) {
case 0:
- _vm->_graphicsManager->setColor(idx, 90, 90, 232);
+ _vm->_screen->setColor(idx, 90, 90, 232);
break;
case 1:
- _vm->_graphicsManager->setColor(idx, 232, 90, 90);
+ _vm->_screen->setColor(idx, 232, 90, 90);
break;
case 2:
- _vm->_graphicsManager->setColor(idx, 90, 232, 90);
+ _vm->_screen->setColor(idx, 90, 232, 90);
break;
case 3:
- _vm->_graphicsManager->setColor(idx, 90, 232, 232);
+ _vm->_screen->setColor(idx, 90, 232, 232);
break;
default:
break;
@@ -564,12 +560,12 @@ void EventsManager::getMouseInfo() {
if (_cursorBlinked) {
_cursorBlinked = false;
- _vm->_graphicsManager->setOneColor(128, 220, 20, 20);
- _vm->_graphicsManager->setColor(128, 220, 20, 20);
+ _vm->_screen->setOneColor(128, 220, 20, 20);
+ _vm->_screen->setColor(128, 220, 20, 20);
} else {
_cursorBlinked = true;
- _vm->_graphicsManager->setOneColor(128, 220, 220, 220);
- _vm->_graphicsManager->setColor(128, 220, 220, 220);
+ _vm->_screen->setOneColor(128, 220, 220, 220);
+ _vm->_screen->setColor(128, 220, 220, 220);
}
}
}
@@ -585,11 +581,11 @@ void EventsManager::getMouseInfo() {
void EventsManager::startCursorBlink() {
if (_vm->_voy->_eventFlags & EVTFLAG_RECORDING) {
- _vm->_graphicsManager->setOneColor(128, 55, 5, 5);
- _vm->_graphicsManager->setColor(128, 220, 20, 20);
+ _vm->_screen->setOneColor(128, 55, 5, 5);
+ _vm->_screen->setColor(128, 220, 20, 20);
_intPtr._hasPalette = true;
- _vm->_graphicsManager->drawDot();
+ _vm->_screen->drawDot();
//copySection();
}
}
diff --git a/engines/voyeur/files.cpp b/engines/voyeur/files.cpp
index 300e086f75..46b195ecaf 100644
--- a/engines/voyeur/files.cpp
+++ b/engines/voyeur/files.cpp
@@ -21,7 +21,7 @@
*/
#include "voyeur/files.h"
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
#include "voyeur/voyeur.h"
#include "voyeur/staticres.h"
@@ -359,7 +359,7 @@ void BoltFile::resolveIt(uint32 id, byte **p) {
}
}
-void BoltFile::resolveFunction(uint32 id, GraphicMethodPtr *fn) {
+void BoltFile::resolveFunction(uint32 id, ScreenMethodPtr *fn) {
if ((int32)id == -1)
*fn = NULL;
else
@@ -485,8 +485,8 @@ void BVoyBoltFile::initViewPortList() {
_state._curMemberPtr->_viewPortListResource = res = new ViewPortListResource(
_state, _state._curMemberPtr->_data);
- _state._vm->_graphicsManager->_viewPortListPtr = res;
- _state._vm->_graphicsManager->_vPort = res->_entries[0];
+ _state._vm->_screen->_viewPortListPtr = res;
+ _state._vm->_screen->_vPort = res->_entries[0];
}
void BVoyBoltFile::initFontInfo() {
@@ -752,24 +752,24 @@ DisplayResource::DisplayResource(VoyeurEngine *vm) {
void DisplayResource::sFillBox(int width, int height) {
assert(_vm);
- bool saveBack = _vm->_graphicsManager->_saveBack;
- _vm->_graphicsManager->_saveBack = false;
+ bool saveBack = _vm->_screen->_saveBack;
+ _vm->_screen->_saveBack = false;
PictureResource pr;
pr._flags = DISPFLAG_1;
pr._select = 0xff;
pr._pick = 0;
- pr._onOff = _vm->_graphicsManager->_drawPtr->_penColor;
+ pr._onOff = _vm->_screen->_drawPtr->_penColor;
pr._bounds = Common::Rect(0, 0, width, height);
- _vm->_graphicsManager->sDrawPic(&pr, this, _vm->_graphicsManager->_drawPtr->_pos);
- _vm->_graphicsManager->_saveBack = saveBack;
+ _vm->_screen->sDrawPic(&pr, this, _vm->_screen->_drawPtr->_pos);
+ _vm->_screen->_saveBack = saveBack;
}
bool DisplayResource::clipRect(Common::Rect &rect) {
Common::Rect clippingRect;
- if (_vm->_graphicsManager->_clipPtr) {
- clippingRect = *_vm->_graphicsManager->_clipPtr;
+ if (_vm->_screen->_clipPtr) {
+ clippingRect = *_vm->_screen->_clipPtr;
} else if (_flags & DISPFLAG_VIEWPORT) {
clippingRect = ((ViewPortResource *)this)->_clipRect;
} else {
@@ -804,18 +804,18 @@ bool DisplayResource::clipRect(Common::Rect &rect) {
}
int DisplayResource::drawText(const Common::String &msg) {
- GraphicsManager &gfxManager = *_vm->_graphicsManager;
- assert(gfxManager._fontPtr);
- assert(gfxManager._fontPtr->_curFont);
- FontInfoResource &fontInfo = *gfxManager._fontPtr;
- PictureResource &fontChar = *_vm->_graphicsManager->_fontChar;
+ Screen &screen = *_vm->_screen;
+ assert(screen._fontPtr);
+ assert(screen._fontPtr->_curFont);
+ FontInfoResource &fontInfo = *screen._fontPtr;
+ PictureResource &fontChar = *_vm->_screen->_fontChar;
FontResource &fontData = *fontInfo._curFont;
int xShadows[9] = { 0, 1, 1, 1, 0, -1, -1, -1, 0 };
int yShadows[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
- Common::Rect *clipPtr = gfxManager._clipPtr;
+ Common::Rect *clipPtr = screen._clipPtr;
if (!(fontInfo._picFlags & DISPFLAG_1))
- gfxManager._clipPtr = NULL;
+ screen._clipPtr = NULL;
int minChar = fontData._minChar;
int padding = fontData._padding;
@@ -834,7 +834,7 @@ int DisplayResource::drawText(const Common::String &msg) {
(ViewPortResource *)this;
if ((fontInfo._fontFlags & DISPFLAG_1) || fontInfo._justify ||
- (gfxManager._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT))) {
+ (screen._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT))) {
msgWidth = viewPort->textWidth(msg);
yp = pos.y;
xp = pos.x;
@@ -898,18 +898,18 @@ int DisplayResource::drawText(const Common::String &msg) {
}
}
- if (gfxManager._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT)) {
+ if (screen._saveBack && fontInfo._fontSaveBack && (_flags & DISPFLAG_VIEWPORT)) {
viewPort->addSaveRect(viewPort->_pageIndex, viewPort->_fontRect);
}
if (fontInfo._fontFlags & DISPFLAG_1) {
- gfxManager._drawPtr->_pos = Common::Point(viewPort->_fontRect.left, viewPort->_fontRect.top);
- gfxManager._drawPtr->_penColor = fontInfo._backColor;
+ screen._drawPtr->_pos = Common::Point(viewPort->_fontRect.left, viewPort->_fontRect.top);
+ screen._drawPtr->_penColor = fontInfo._backColor;
sFillBox(viewPort->_fontRect.width(), viewPort->_fontRect.height());
}
- bool saveBack = gfxManager._saveBack;
- gfxManager._saveBack = false;
+ bool saveBack = screen._saveBack;
+ screen._saveBack = false;
int count = 0;
if (fontInfo._fontFlags & DISPFLAG_4)
@@ -970,7 +970,7 @@ int DisplayResource::drawText(const Common::String &msg) {
uint16 offset = READ_LE_UINT16(fontData._charOffsets + charValue * 2);
fontChar._imgData = fontData._charImages + offset * 2;
- gfxManager.sDrawPic(&fontChar, this, Common::Point(xp, yp));
+ screen.sDrawPic(&fontChar, this, Common::Point(xp, yp));
fontChar._imgData = NULL;
xp += charWidth + padding;
@@ -982,8 +982,8 @@ int DisplayResource::drawText(const Common::String &msg) {
if (fontInfo._justify == ALIGN_LEFT)
fontInfo._pos.x = xp;
- gfxManager._saveBack = saveBack;
- gfxManager._clipPtr = clipPtr;
+ screen._saveBack = saveBack;
+ screen._clipPtr = clipPtr;
return msgWidth;
}
@@ -993,7 +993,7 @@ int DisplayResource::textWidth(const Common::String &msg) {
return 0;
const char *msgP = msg.c_str();
- FontResource &fontData = *_vm->_graphicsManager->_fontPtr->_curFont;
+ FontResource &fontData = *_vm->_screen->_fontPtr->_curFont;
int minChar = fontData._minChar;
int maxChar = fontData._maxChar;
int padding = fontData._padding;
@@ -1085,9 +1085,9 @@ PictureResource::PictureResource(BoltFilesState &state, const byte *src):
mode = 226;
}
- if (mode != state._vm->_graphicsManager->_SVGAMode) {
- state._vm->_graphicsManager->_SVGAMode = mode;
- state._vm->_graphicsManager->clearPalette();
+ if (mode != state._vm->_screen->_SVGAMode) {
+ state._vm->_screen->_SVGAMode = mode;
+ state._vm->_screen->clearPalette();
}
int screenOffset = READ_LE_UINT32(&src[18]) & 0xffff;
@@ -1096,13 +1096,14 @@ PictureResource::PictureResource(BoltFilesState &state, const byte *src):
if (_flags & PICFLAG_CLEAR_SCREEN) {
// Clear screen picture. That's right. This game actually has a picture
// resource flag to clear the screen! Bizarre.
- Graphics::Surface &s = state._vm->_graphicsManager->_screenSurface;
- s.fillRect(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), 0);
+ state._vm->_screen->clear();
} else {
// Direct screen loading picture. In this case, the raw data of the resource
// is directly decompressed into the screen surface. Again, bizarre.
- byte *pDest = (byte *)state._vm->_graphicsManager->_screenSurface.getPixels();
+ Screen &screen = *state._vm->_screen;
+ byte *pDest = (byte *)screen.getPixels();
state.decompress(pDest, SCREEN_WIDTH * SCREEN_HEIGHT, state._curMemberPtr->_mode);
+ screen.markAllDirty();
}
} else {
if (_flags & PICFLAG_CLEAR_SCREEN00) {
@@ -1249,13 +1250,13 @@ ViewPortResource::ViewPortResource(BoltFilesState &state, const byte *src):
ys + READ_LE_UINT16(src + 0x4C));
state._curLibPtr->resolveIt(READ_LE_UINT32(src + 0x7A), &dummy);
- state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x7E), (GraphicMethodPtr *)&_fn1);
- state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x82), (GraphicMethodPtr *)&_setupFn);
- state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x86), (GraphicMethodPtr *)&_addFn);
- state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x8A), (GraphicMethodPtr *)&_restoreFn);
+ state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x7E), (ScreenMethodPtr *)&_fn1);
+ state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x82), (ScreenMethodPtr *)&_setupFn);
+ state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x86), (ScreenMethodPtr *)&_addFn);
+ state._curLibPtr->resolveFunction(READ_LE_UINT32(src + 0x8A), (ScreenMethodPtr *)&_restoreFn);
if (!_restoreFn && _addFn)
- _addFn = &GraphicsManager::addRectNoSaveBack;
+ _addFn = &Screen::addRectNoSaveBack;
}
ViewPortResource::~ViewPortResource() {
@@ -1327,19 +1328,19 @@ void ViewPortResource::setupViewPort(PictureResource *page, Common::Rect *clippi
_restoreFn = restoreFn;
if (setupFn)
- (_state._vm->_graphicsManager->*setupFn)(this);
+ (_state._vm->_screen->*setupFn)(this);
}
void ViewPortResource::setupViewPort() {
- setupViewPort(_state._vm->_graphicsManager->_backgroundPage, NULL,
- &GraphicsManager::setupMCGASaveRect, &GraphicsManager::addRectOptSaveRect,
- &GraphicsManager::restoreMCGASaveRect);
+ setupViewPort(_state._vm->_screen->_backgroundPage, NULL,
+ &Screen::setupMCGASaveRect, &Screen::addRectOptSaveRect,
+ &Screen::restoreMCGASaveRect);
}
void ViewPortResource::setupViewPort(PictureResource *pic, Common::Rect *clippingRect) {
setupViewPort(pic, clippingRect,
- &GraphicsManager::setupMCGASaveRect, &GraphicsManager::addRectOptSaveRect,
- &GraphicsManager::restoreMCGASaveRect);
+ &Screen::setupMCGASaveRect, &Screen::addRectOptSaveRect,
+ &Screen::restoreMCGASaveRect);
}
void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) {
@@ -1347,7 +1348,7 @@ void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) {
if (clipRect(rect)) {
if (_addFn) {
- (_state._vm->_graphicsManager->*_addFn)(this, pageIndex, rect);
+ (_state._vm->_screen->*_addFn)(this, pageIndex, rect);
} else if (_rectListCount[pageIndex] != -1) {
_rectListPtr[pageIndex]->push_back(rect);
}
@@ -1355,26 +1356,26 @@ void ViewPortResource::addSaveRect(int pageIndex, const Common::Rect &r) {
}
void ViewPortResource::fillPic(byte onOff) {
- _state._vm->_graphicsManager->fillPic(this, onOff);
+ _state._vm->_screen->fillPic(this, onOff);
}
void ViewPortResource::drawIfaceTime() {
// Hour display
- _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort,
+ _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort,
(_state._vm->_gameHour / 10) == 0 ? 10 : _state._vm->_gameHour / 10,
Common::Point(161, 25));
- _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort,
+ _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort,
_state._vm->_gameHour % 10, Common::Point(172, 25));
// Minute display
- _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort,
+ _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort,
_state._vm->_gameMinute / 10, Common::Point(190, 25));
- _state._vm->_graphicsManager->drawANumber(_state._vm->_graphicsManager->_vPort,
+ _state._vm->_screen->drawANumber(_state._vm->_screen->_vPort,
_state._vm->_gameMinute % 10, Common::Point(201, 25));
// AM/PM indicator
PictureResource *pic = _state._vm->_bVoy->boltEntry(_state._vm->_voy->_isAM ? 272 : 273)._picResource;
- _state._vm->_graphicsManager->sDrawPic(pic, _state._vm->_graphicsManager->_vPort,
+ _state._vm->_screen->sDrawPic(pic, _state._vm->_screen->_vPort,
Common::Point(215, 27));
}
@@ -1382,9 +1383,9 @@ void ViewPortResource::drawPicPerm(PictureResource *pic, const Common::Point &pt
Common::Rect bounds = pic->_bounds;
bounds.translate(pt.x, pt.y);
- bool saveBack = _state._vm->_graphicsManager->_saveBack;
- _state._vm->_graphicsManager->_saveBack = false;
- _state._vm->_graphicsManager->sDrawPic(pic, this, pt);
+ bool saveBack = _state._vm->_screen->_saveBack;
+ _state._vm->_screen->_saveBack = false;
+ _state._vm->_screen->sDrawPic(pic, this, pt);
clipRect(bounds);
for (int pageIndex = 0; pageIndex < _pageCount; ++pageIndex) {
@@ -1393,7 +1394,7 @@ void ViewPortResource::drawPicPerm(PictureResource *pic, const Common::Point &pt
}
}
- _state._vm->_graphicsManager->_saveBack = saveBack;
+ _state._vm->_screen->_saveBack = saveBack;
}
/*------------------------------------------------------------------------*/
@@ -1526,7 +1527,7 @@ CMapResource::CMapResource(BoltFilesState &state, const byte *src): _vm(state._v
_entries = new byte[count * 3];
Common::copy(src + 6, src + 6 + 3 * count, _entries);
- int palIndex = state._vm->_graphicsManager->_viewPortListPtr->_palIndex;
+ int palIndex = state._vm->_screen->_viewPortListPtr->_palIndex;
if (_end > palIndex)
_end = palIndex;
if (_start > palIndex)
diff --git a/engines/voyeur/files.h b/engines/voyeur/files.h
index eef5df497c..92b43958d3 100644
--- a/engines/voyeur/files.h
+++ b/engines/voyeur/files.h
@@ -27,7 +27,7 @@
#include "common/file.h"
#include "common/rect.h"
#include "common/str.h"
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
namespace Voyeur {
@@ -112,7 +112,7 @@ public:
byte *memberAddr(uint32 id);
byte *memberAddrOffset(uint32 id);
void resolveIt(uint32 id, byte **p);
- void resolveFunction(uint32 id, GraphicMethodPtr *fn);
+ void resolveFunction(uint32 id, ScreenMethodPtr *fn);
BoltEntry &boltEntry(uint16 id);
BoltEntry &getBoltEntryFromLong(uint32 id);
@@ -325,9 +325,13 @@ private:
ViewPortAddPtr addFn, ViewPortRestorePtr restoreFn);
public:
ViewPortResource *_parent;
+ ViewPortSetupPtr _setupFn;
int _pageCount;
+ ViewPortAddPtr _addFn;
int _pageIndex;
+ ViewPortRestorePtr _restoreFn;
int _lastPage;
+ ScreenMethodPtr _fn1;
Common::Rect _bounds;
PictureResource *_currentPic;
PictureResource *_activePage;
@@ -340,10 +344,6 @@ public:
int _rectListCount[3];
Common::Rect _clipRect;
- GraphicMethodPtr _fn1;
- ViewPortSetupPtr _setupFn;
- ViewPortAddPtr _addFn;
- ViewPortRestorePtr _restoreFn;
Common::Rect _fontRect;
public:
ViewPortResource(BoltFilesState &state, const byte *src);
diff --git a/engines/voyeur/files_threads.cpp b/engines/voyeur/files_threads.cpp
index 9908324043..bbd3dfe4e9 100644
--- a/engines/voyeur/files_threads.cpp
+++ b/engines/voyeur/files_threads.cpp
@@ -21,7 +21,7 @@
*/
#include "voyeur/files.h"
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
#include "voyeur/voyeur.h"
#include "voyeur/staticres.h"
@@ -461,7 +461,7 @@ void ThreadResource::parsePlayCommands() {
pic = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + i * 2)._picResource;
pal = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + i * 2 + 1)._cMapResource;
- _vm->_graphicsManager->_vPort->setupViewPort(pic);
+ _vm->_screen->_vPort->setupViewPort(pic);
pal->startFade();
_vm->flipPageAndWaitForFade();
@@ -980,10 +980,10 @@ int ThreadResource::doApt() {
_vm->_soundManager->startVOCPlay(_vm->_soundManager->getVOCFileName(_vm->_currentVocId));
_vm->_currentVocId = 151;
- _vm->_graphicsManager->setColor(129, 82, 82, 82);
- _vm->_graphicsManager->setColor(130, 112, 112, 112);
- _vm->_graphicsManager->setColor(131, 215, 215, 215);
- _vm->_graphicsManager->setColor(132, 235, 235, 235);
+ _vm->_screen->setColor(129, 82, 82, 82);
+ _vm->_screen->setColor(130, 112, 112, 112);
+ _vm->_screen->setColor(131, 215, 215, 215);
+ _vm->_screen->setColor(132, 235, 235, 235);
_vm->_eventsManager->_intPtr._hasPalette = true;
@@ -1044,7 +1044,7 @@ int ThreadResource::doApt() {
// Draw the text description for the highlighted hotspot
pic = _vm->_bVoy->boltEntry(_vm->_playStampGroupId +
hotspotId + 6)._picResource;
- _vm->_graphicsManager->sDrawPic(pic, _vm->_graphicsManager->_vPort,
+ _vm->_screen->sDrawPic(pic, _vm->_screen->_vPort,
Common::Point(106, 200));
}
@@ -1112,10 +1112,10 @@ void ThreadResource::doRoom() {
if (!vm._bVoy->getBoltGroup(vm._playStampGroupId))
return;
- vm._graphicsManager->_backColors = vm._bVoy->boltEntry(vm._playStampGroupId + 1)._cMapResource;
- vm._graphicsManager->_backgroundPage = vm._bVoy->boltEntry(vm._playStampGroupId)._picResource;
- vm._graphicsManager->_vPort->setupViewPort(vm._graphicsManager->_backgroundPage);
- vm._graphicsManager->_backColors->startFade();
+ vm._screen->_backColors = vm._bVoy->boltEntry(vm._playStampGroupId + 1)._cMapResource;
+ vm._screen->_backgroundPage = vm._bVoy->boltEntry(vm._playStampGroupId)._picResource;
+ vm._screen->_vPort->setupViewPort(vm._screen->_backgroundPage);
+ vm._screen->_backColors->startFade();
voy._fadingStep1 = 2;
voy._fadingStep2 = 0;
@@ -1144,7 +1144,7 @@ void ThreadResource::doRoom() {
bool breakFlag = false;
while (!vm.shouldQuit() && !breakFlag) {
_vm->_voyeurArea = AREA_ROOM;
- vm._graphicsManager->setColor(128, 0, 255, 0);
+ vm._screen->setColor(128, 0, 255, 0);
vm._eventsManager->_intPtr._hasPalette = true;
do {
@@ -1186,7 +1186,7 @@ void ThreadResource::doRoom() {
}
vm._eventsManager->_intPtr._hasPalette = true;
- vm._graphicsManager->flipPage();
+ vm._screen->flipPage();
vm._eventsManager->sWaitFlip();
} while (!vm.shouldQuit() && !vm._eventsManager->_mouseClicked);
@@ -1234,13 +1234,13 @@ void ThreadResource::doRoom() {
// WORKAROUND: Skipped code from the original, that freed the group,
// reloaded it, and reloaded the cursors
- vm._graphicsManager->_backColors = vm._bVoy->boltEntry(
+ vm._screen->_backColors = vm._bVoy->boltEntry(
vm._playStampGroupId + 1)._cMapResource;
- vm._graphicsManager->_backgroundPage = vm._bVoy->boltEntry(
+ vm._screen->_backgroundPage = vm._bVoy->boltEntry(
vm._playStampGroupId)._picResource;
- vm._graphicsManager->_vPort->setupViewPort();
- vm._graphicsManager->_backColors->startFade();
+ vm._screen->_vPort->setupViewPort();
+ vm._screen->_backColors->startFade();
_vm->flipPageAndWait();
while (!vm.shouldQuit() && (vm._eventsManager->_fadeStatus & 1))
@@ -1265,7 +1265,7 @@ void ThreadResource::doRoom() {
_vm->flipPageAndWait();
- vm._graphicsManager->fadeUpICF1();
+ vm._screen->fadeUpICF1();
voy._eventFlags &= EVTFLAG_RECORDING;
vm._eventsManager->showCursor();
}
@@ -1350,7 +1350,7 @@ int ThreadResource::doInterface() {
_vm->_soundManager->startVOCPlay(fname);
_vm->_eventsManager->getMouseInfo();
- _vm->_graphicsManager->setColor(240, 220, 220, 220);
+ _vm->_screen->setColor(240, 220, 220, 220);
_vm->_eventsManager->_intPtr._hasPalette = true;
_vm->_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED;
@@ -1424,20 +1424,20 @@ int ThreadResource::doInterface() {
// Regularly update the time display
if (_vm->_voy->_RTANum & 2) {
- _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort,
+ _vm->_screen->drawANumber(_vm->_screen->_vPort,
_vm->_gameMinute / 10, Common::Point(190, 25));
- _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort,
+ _vm->_screen->drawANumber(_vm->_screen->_vPort,
_vm->_gameMinute % 10, Common::Point(201, 25));
if (_vm->_voy->_RTANum & 4) {
int v = _vm->_gameHour / 10;
- _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort,
+ _vm->_screen->drawANumber(_vm->_screen->_vPort,
v == 0 ? 10 : v, Common::Point(161, 25));
- _vm->_graphicsManager->drawANumber(_vm->_graphicsManager->_vPort,
+ _vm->_screen->drawANumber(_vm->_screen->_vPort,
_vm->_gameHour % 10, Common::Point(172, 25));
pic = _vm->_bVoy->boltEntry(_vm->_voy->_isAM ? 272 : 273)._picResource;
- _vm->_graphicsManager->sDrawPic(pic, _vm->_graphicsManager->_vPort,
+ _vm->_screen->sDrawPic(pic, _vm->_screen->_vPort,
Common::Point(215, 27));
}
}
@@ -1605,16 +1605,16 @@ void ThreadResource::loadTheApt() {
_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId);
_vm->_voy->_aptLoadMode = -1;
- _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(
+ _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(
_vm->_playStampGroupId + 5)._picResource;
- _vm->_graphicsManager->_vPort->setupViewPort(
- _vm->_graphicsManager->_backgroundPage);
+ _vm->_screen->_vPort->setupViewPort(
+ _vm->_screen->_backgroundPage);
} else {
_vm->_bVoy->getBoltGroup(_vm->_playStampGroupId);
- _vm->_graphicsManager->_backgroundPage = _vm->_bVoy->boltEntry(
+ _vm->_screen->_backgroundPage = _vm->_bVoy->boltEntry(
_vm->_playStampGroupId + 5)._picResource;
- _vm->_graphicsManager->_vPort->setupViewPort(
- _vm->_graphicsManager->_backgroundPage);
+ _vm->_screen->_vPort->setupViewPort(
+ _vm->_screen->_backgroundPage);
}
CMapResource *pal = _vm->_bVoy->boltEntry(_vm->_playStampGroupId + 4)._cMapResource;
@@ -1624,10 +1624,10 @@ void ThreadResource::loadTheApt() {
}
void ThreadResource::freeTheApt() {
- _vm->_graphicsManager->fadeDownICF1(5);
+ _vm->_screen->fadeDownICF1(5);
_vm->flipPageAndWaitForFade();
- _vm->_graphicsManager->fadeUpICF1();
+ _vm->_screen->fadeUpICF1();
if (_vm->_currentVocId != -1) {
_vm->_soundManager->stopVOCPlay();
@@ -1635,17 +1635,17 @@ void ThreadResource::freeTheApt() {
}
if (_vm->_voy->_aptLoadMode == -1) {
- _vm->_graphicsManager->fadeDownICF(6);
+ _vm->_screen->fadeDownICF(6);
} else {
doAptAnim(2);
}
if (_vm->_voy->_aptLoadMode == 140) {
- _vm->_graphicsManager->screenReset();
- _vm->_graphicsManager->resetPalette();
+ _vm->_screen->screenReset();
+ _vm->_screen->resetPalette();
}
- _vm->_graphicsManager->_vPort->setupViewPort(nullptr);
+ _vm->_screen->_vPort->setupViewPort(nullptr);
_vm->_bVoy->freeBoltGroup(_vm->_playStampGroupId);
_vm->_playStampGroupId = -1;
_vm->_voy->_viewBounds = nullptr;
@@ -1705,7 +1705,7 @@ void ThreadResource::doAptAnim(int mode) {
for (int idx = 0; (idx < 6) && !_vm->shouldQuit(); ++idx) {
PictureResource *pic = _vm->_bVoy->boltEntry(id + idx + 1)._picResource;
- _vm->_graphicsManager->_vPort->setupViewPort(pic);
+ _vm->_screen->_vPort->setupViewPort(pic);
pal->startFade();
_vm->flipPageAndWait();
diff --git a/engines/voyeur/module.mk b/engines/voyeur/module.mk
index aab254cf36..a38bdd9ab2 100644
--- a/engines/voyeur/module.mk
+++ b/engines/voyeur/module.mk
@@ -8,7 +8,7 @@ MODULE_OBJS := \
events.o \
files.o \
files_threads.o \
- graphics.o \
+ screen.o \
sound.o \
staticres.o \
voyeur.o \
diff --git a/engines/voyeur/graphics.cpp b/engines/voyeur/screen.cpp
index a20e9f6006..62f609c5c7 100644
--- a/engines/voyeur/graphics.cpp
+++ b/engines/voyeur/screen.cpp
@@ -20,7 +20,7 @@
*
*/
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
#include "voyeur/voyeur.h"
#include "voyeur/staticres.h"
#include "engines/util.h"
@@ -38,7 +38,8 @@ DrawInfo::DrawInfo(int penColor, const Common::Point &pos) {
/*------------------------------------------------------------------------*/
-GraphicsManager::GraphicsManager(VoyeurEngine *vm) : _defaultDrawInfo(1, Common::Point()), _drawPtr(&_defaultDrawInfo), _vm(vm) {
+Screen::Screen(VoyeurEngine *vm) : Graphics::Screen(), _vm(vm), _drawPtr(&_defaultDrawInfo),
+ _defaultDrawInfo(1, Common::Point()) {
_SVGAMode = 0;
_planeSelect = 0;
_saveBack = true;
@@ -52,18 +53,17 @@ GraphicsManager::GraphicsManager(VoyeurEngine *vm) : _defaultDrawInfo(1, Common:
_backColors = nullptr;
}
-void GraphicsManager::sInitGraphics() {
+void Screen::sInitGraphics() {
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, false);
- _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
+ create(SCREEN_WIDTH, SCREEN_HEIGHT);
clearPalette();
}
-GraphicsManager::~GraphicsManager() {
- _screenSurface.free();
+Screen::~Screen() {
delete _fontChar;
}
-void GraphicsManager::setupMCGASaveRect(ViewPortResource *viewPort) {
+void Screen::setupMCGASaveRect(ViewPortResource *viewPort) {
if (viewPort->_activePage) {
viewPort->_activePage->_flags |= DISPFLAG_1;
Common::Rect *clipRect = _clipPtr;
@@ -77,7 +77,7 @@ void GraphicsManager::setupMCGASaveRect(ViewPortResource *viewPort) {
viewPort->_rectListCount[1] = -1;
}
-void GraphicsManager::addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) {
+void Screen::addRectOptSaveRect(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) {
if (viewPort->_rectListCount[idx] == -1)
return;
@@ -86,7 +86,7 @@ void GraphicsManager::addRectOptSaveRect(ViewPortResource *viewPort, int idx, co
++viewPort->_rectListCount[idx];
}
-void GraphicsManager::restoreMCGASaveRect(ViewPortResource *viewPort) {
+void Screen::restoreMCGASaveRect(ViewPortResource *viewPort) {
if (viewPort->_rectListCount[0] != -1) {
for (int i = 0; i < viewPort->_rectListCount[0]; ++i) {
addRectOptSaveRect(viewPort, 1, (*viewPort->_rectListPtr[0])[i]);
@@ -106,11 +106,11 @@ void GraphicsManager::restoreMCGASaveRect(ViewPortResource *viewPort) {
viewPort->_rectListCount[1] = count;
}
-void GraphicsManager::addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) {
+void Screen::addRectNoSaveBack(ViewPortResource *viewPort, int idx, const Common::Rect &bounds) {
// Stubbed/dummy method in the original.
}
-void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay,
+void Screen::sDrawPic(DisplayResource *srcDisplay, DisplayResource *destDisplay,
const Common::Point &initialOffset) {
int width1, width2;
int widthDiff, widthDiff2;
@@ -128,7 +128,8 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
int runLength;
byte *srcImgData, *destImgData;
- byte *srcP, *destP;
+ const byte *srcP;
+ byte *destP;
byte byteVal, byteVal2;
PictureResource *srcPic;
@@ -292,7 +293,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
// loc_2566F
if (srcFlags & DISPFLAG_2) {
// loc_256FA
- srcP = (byte *)_screenSurface.getPixels() + srcOffset;
+ srcP = (const byte *)getPixels() + srcOffset;
for (int yp = 0; yp < height1; ++yp) {
for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
@@ -325,13 +326,16 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
}
} else {
// loc_25829
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
Common::copy(srcP, srcP + width2, destP);
srcP += width2 + widthDiff;
destP += width2 + widthDiff2;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
}
}
} else {
@@ -341,13 +345,16 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
error("TODO: sDrawPic variation");
} else {
// loc_2606D
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
Common::copy(srcP, srcP + width2, destP);
destP += width2 + widthDiff2;
srcP += width2 + widthDiff;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
}
}
} else {
@@ -530,11 +537,14 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
// loc_27477
if (destFlags & DISPFLAG_8) {
// loc_27481
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
Common::fill(destP, destP + width2, onOff);
destP += width2 + widthDiff2;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
} else {
// loc_2753C
destP = destImgData + screenOffset;
@@ -561,7 +571,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
if (srcFlags & PICFLAG_100) {
if (isClipped) {
// loc_266E3
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
tmpWidth = (tmpWidth < 0) ? -tmpWidth : 0;
int xMax = tmpWidth + width2;
tmpHeight = (tmpHeight < 0) ? -tmpHeight : 0;
@@ -592,9 +602,12 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
if (yp >= tmpHeight)
destP += widthDiff2;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
} else {
// loc_26815
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
for (int xi = 0; xi < width2; ++xi, ++destP) {
@@ -618,10 +631,13 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
destP += widthDiff2;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
}
} else {
// Direct screen write
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
@@ -631,6 +647,9 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
destP += widthDiff2;
srcP += widthDiff;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
}
} else if (srcFlags & PICFLAG_100) {
srcP = srcImgData;
@@ -663,7 +682,7 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
}
} else {
// loc_26BD5
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
byteVal2 = 0;
@@ -684,10 +703,13 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
destP += widthDiff2;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
}
} else {
// loc_26C9A
- destP = (byte *)_screenSurface.getPixels() + screenOffset;
+ destP = (byte *)getPixels() + screenOffset;
for (int yp = 0; yp < height1; ++yp) {
for (int xp = 0; xp < width2; ++xp, ++srcP, ++destP) {
@@ -696,6 +718,9 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
destP += widthDiff2;
srcP += widthDiff;
}
+
+ addDirtyRect(Common::Rect(offset.x, offset.y, offset.x + width2,
+ offset.y + height1));
}
} else {
// loc_26D2F
@@ -850,12 +875,12 @@ void GraphicsManager::sDrawPic(DisplayResource *srcDisplay, DisplayResource *des
}
}
-void GraphicsManager::drawANumber(DisplayResource *display, int num, const Common::Point &pt) {
+void Screen::drawANumber(DisplayResource *display, int num, const Common::Point &pt) {
PictureResource *pic = _vm->_bVoy->boltEntry(num + 261)._picResource;
sDrawPic(pic, display, pt);
}
-void GraphicsManager::fillPic(DisplayResource *display, byte onOff) {
+void Screen::fillPic(DisplayResource *display, byte onOff) {
PictureResource *pic;
if (display->_flags & DISPFLAG_VIEWPORT) {
pic = ((ViewPortResource *)display)->_currentPic;
@@ -876,11 +901,11 @@ void GraphicsManager::fillPic(DisplayResource *display, byte onOff) {
/**
* Queues the given picture for display
*/
-void GraphicsManager::sDisplayPic(PictureResource *pic) {
+void Screen::sDisplayPic(PictureResource *pic) {
_vm->_eventsManager->_intPtr._flipWait = true;
}
-void GraphicsManager::flipPage() {
+void Screen::flipPage() {
Common::Array<ViewPortResource *> &viewPorts = _viewPortListPtr->_entries;
bool flipFlag = false;
@@ -907,7 +932,7 @@ void GraphicsManager::flipPage() {
}
}
-void GraphicsManager::restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount,
+void Screen::restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount,
PictureResource *srcPic, PictureResource *destPic) {
// WORKAROUND: Since _backgroundPage can point to a resource freed at the end of display methods,
// I'm now explicitly resetting it to null in screenReset(), so at this point it can be null
@@ -929,33 +954,26 @@ void GraphicsManager::restoreBack(Common::Array<Common::Rect> &rectList, int rec
_saveBack = saveBack;
}
-void GraphicsManager::clearPalette() {
- byte palette[768];
- Common::fill(&palette[0], &palette[768], 0);
- g_system->getPaletteManager()->setPalette(&palette[0], 0, 256);
-}
-
-void GraphicsManager::setPalette(const byte *palette, int start, int count) {
- g_system->getPaletteManager()->setPalette(palette, start, count);
+void Screen::setPalette(const byte *palette, int start, int count) {
+ Graphics::Screen::setPalette(palette, start, count);
_vm->_eventsManager->_gameData._hasPalette = false;
}
-void GraphicsManager::setPalette128(const byte *palette, int start, int count) {
+void Screen::setPalette128(const byte *palette, int start, int count) {
byte rgb[3];
- g_system->getPaletteManager()->grabPalette(&rgb[0], 128, 1);
- g_system->getPaletteManager()->setPalette(palette, start, count);
- g_system->getPaletteManager()->setPalette(&rgb[0], 128, 1);
+ getPalette(&rgb[0], 128, 1);
+ Graphics::Screen::setPalette(palette, start, count);
+ Graphics::Screen::setPalette(&rgb[0], 128, 1);
}
-
-void GraphicsManager::resetPalette() {
+void Screen::resetPalette() {
for (int i = 0; i < 256; ++i)
setColor(i, 0, 0, 0);
_vm->_eventsManager->_intPtr._hasPalette = true;
}
-void GraphicsManager::setColor(int idx, byte r, byte g, byte b) {
+void Screen::setColor(int idx, byte r, byte g, byte b) {
byte *vgaP = &_VGAColors[idx * 3];
vgaP[0] = r;
vgaP[1] = g;
@@ -965,7 +983,7 @@ void GraphicsManager::setColor(int idx, byte r, byte g, byte b) {
_vm->_eventsManager->_intPtr._palEndIndex = MAX(_vm->_eventsManager->_intPtr._palEndIndex, idx);
}
-void GraphicsManager::setOneColor(int idx, byte r, byte g, byte b) {
+void Screen::setOneColor(int idx, byte r, byte g, byte b) {
byte palEntry[3];
palEntry[0] = r;
palEntry[1] = g;
@@ -973,7 +991,7 @@ void GraphicsManager::setOneColor(int idx, byte r, byte g, byte b) {
g_system->getPaletteManager()->setPalette(&palEntry[0], idx, 1);
}
-void GraphicsManager::setColors(int start, int count, const byte *pal) {
+void Screen::setColors(int start, int count, const byte *pal) {
for (int i = 0; i < count; ++i) {
if ((i + start) != 128) {
const byte *rgb = pal + i * 3;
@@ -984,7 +1002,7 @@ void GraphicsManager::setColors(int start, int count, const byte *pal) {
_vm->_eventsManager->_intPtr._hasPalette = true;
}
-void GraphicsManager::screenReset() {
+void Screen::screenReset() {
resetPalette();
_backgroundPage = NULL;
@@ -994,7 +1012,7 @@ void GraphicsManager::screenReset() {
_vm->flipPageAndWait();
}
-void GraphicsManager::fadeDownICF1(int steps) {
+void Screen::fadeDownICF1(int steps) {
if (steps > 0) {
int stepAmount = _vm->_voy->_fadingAmount2 / steps;
@@ -1007,7 +1025,7 @@ void GraphicsManager::fadeDownICF1(int steps) {
_vm->_voy->_fadingAmount2 = 0;
}
-void GraphicsManager::fadeUpICF1(int steps) {
+void Screen::fadeUpICF1(int steps) {
if (steps > 0) {
int stepAmount = (63 - _vm->_voy->_fadingAmount2) / steps;
@@ -1020,7 +1038,7 @@ void GraphicsManager::fadeUpICF1(int steps) {
_vm->_voy->_fadingAmount2 = 63;
}
-void GraphicsManager::fadeDownICF(int steps) {
+void Screen::fadeDownICF(int steps) {
if (steps > 0) {
_vm->_eventsManager->hideCursor();
int stepAmount1 = _vm->_voy->_fadingAmount1 / steps;
@@ -1037,14 +1055,19 @@ void GraphicsManager::fadeDownICF(int steps) {
_vm->_voy->_fadingAmount2 = 0;
}
-void GraphicsManager::drawDot() {
- for (int y = 0; y < 9; ++y) {
- byte *pDest = (byte *)_screenSurface.getPixels() + DOT_LINE_START[y] + DOT_LINE_OFFSET[y];
- Common::fill(pDest, pDest + DOT_LINE_LENGTH[y], 0x80);
+void Screen::drawDot() {
+ for (int idx = 0; idx < 9; ++idx) {
+ uint offset = DOT_LINE_START[idx] + DOT_LINE_OFFSET[idx];
+ int xp = offset % SCREEN_WIDTH;
+ int yp = offset / SCREEN_WIDTH;
+
+ byte *pDest = (byte *)getPixels() + offset;
+ Common::fill(pDest, pDest + DOT_LINE_LENGTH[idx], 0x80);
+ addDirtyRect(Common::Rect(xp, yp, xp + DOT_LINE_LENGTH[idx], yp + 1));
}
}
-void GraphicsManager::synchronize(Common::Serializer &s) {
+void Screen::synchronize(Common::Serializer &s) {
s.syncBytes(&_VGAColors[0], PALETTE_SIZE);
}
diff --git a/engines/voyeur/graphics.h b/engines/voyeur/screen.h
index e4d0b38650..aaf61747a4 100644
--- a/engines/voyeur/graphics.h
+++ b/engines/voyeur/screen.h
@@ -27,17 +27,15 @@
#include "common/array.h"
#include "common/rect.h"
#include "common/serializer.h"
-#include "graphics/surface.h"
+#include "graphics/screen.h"
namespace Voyeur {
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200
-#define PALETTE_COUNT 256
-#define PALETTE_SIZE (256 * 3)
class VoyeurEngine;
-class GraphicsManager;
+class Screen;
class DisplayResource;
class PictureResource;
class ViewPortResource;
@@ -54,12 +52,12 @@ public:
DrawInfo(int penColor, const Common::Point &pos);
};
-typedef void (GraphicsManager::*GraphicMethodPtr)();
-typedef void (GraphicsManager::*ViewPortSetupPtr)(ViewPortResource *);
-typedef void (GraphicsManager::*ViewPortAddPtr)(ViewPortResource *, int idx, const Common::Rect &bounds);
-typedef void (GraphicsManager::*ViewPortRestorePtr)(ViewPortResource *);
+typedef void (Screen::*ScreenMethodPtr)();
+typedef void (Screen::*ViewPortSetupPtr)(ViewPortResource *);
+typedef void (Screen::*ViewPortAddPtr)(ViewPortResource *, int idx, const Common::Rect &bounds);
+typedef void (Screen::*ViewPortRestorePtr)(ViewPortResource *);
-class GraphicsManager {
+class Screen: public Graphics::Screen {
public:
byte _VGAColors[PALETTE_SIZE];
PictureResource *_backgroundPage;
@@ -69,7 +67,6 @@ public:
bool _saveBack;
Common::Rect *_clipPtr;
uint _planeSelect;
- Graphics::Surface _screenSurface;
CMapResource *_backColors;
FontInfoResource *_fontPtr;
PictureResource *_fontChar;
@@ -81,8 +78,8 @@ private:
void restoreBack(Common::Array<Common::Rect> &rectList, int rectListCount,
PictureResource *srcPic, PictureResource *destPic);
public:
- GraphicsManager(VoyeurEngine *vm);
- ~GraphicsManager();
+ Screen(VoyeurEngine *vm);
+ virtual ~Screen();
void sInitGraphics();
@@ -96,7 +93,6 @@ public:
void sDisplayPic(PictureResource *pic);
void drawANumber(DisplayResource *display, int num, const Common::Point &pt);
void flipPage();
- void clearPalette();
void setPalette(const byte *palette, int start, int count);
void setPalette128(const byte *palette, int start, int count);
void resetPalette();
diff --git a/engines/voyeur/sound.cpp b/engines/voyeur/sound.cpp
index f47fdde3e1..483dfc7cbc 100644
--- a/engines/voyeur/sound.cpp
+++ b/engines/voyeur/sound.cpp
@@ -22,6 +22,8 @@
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
+#include "audio/decoders/voc.h"
+#include "common/file.h"
#include "common/memstream.h"
#include "voyeur/sound.h"
#include "voyeur/staticres.h"
diff --git a/engines/voyeur/sound.h b/engines/voyeur/sound.h
index af1d0b1b46..fd1d126ef0 100644
--- a/engines/voyeur/sound.h
+++ b/engines/voyeur/sound.h
@@ -26,8 +26,6 @@
#include "common/scummsys.h"
#include "common/str.h"
#include "audio/mixer.h"
-#include "audio/decoders/voc.h"
-#include "voyeur/files.h"
namespace Voyeur {
diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp
index cbb6846340..01b76a72d1 100644
--- a/engines/voyeur/voyeur.cpp
+++ b/engines/voyeur/voyeur.cpp
@@ -22,7 +22,7 @@
#include "voyeur/voyeur.h"
#include "voyeur/animation.h"
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
#include "voyeur/staticres.h"
#include "common/scummsys.h"
#include "common/config-manager.h"
@@ -40,7 +40,7 @@ VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc)
_debugger = nullptr;
_eventsManager = nullptr;
_filesManager = nullptr;
- _graphicsManager = nullptr;
+ _screen = nullptr;
_soundManager = nullptr;
_voy = nullptr;
_bVoy = NULL;
@@ -65,13 +65,6 @@ VoyeurEngine::VoyeurEngine(OSystem *syst, const VoyeurGameDescription *gameDesc)
DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts");
- _debugger = new Debugger(this);
- _eventsManager = new EventsManager(this);
- _filesManager = new FilesManager(this);
- _graphicsManager = new GraphicsManager(this);
- _soundManager = new SoundManager(_mixer);
- _voy = new SVoy(this);
-
_stampLibPtr = nullptr;
_controlGroupPtr = nullptr;
_stampData = nullptr;
@@ -88,7 +81,7 @@ VoyeurEngine::~VoyeurEngine() {
delete _bVoy;
delete _voy;
delete _soundManager;
- delete _graphicsManager;
+ delete _screen;
delete _filesManager;
delete _eventsManager;
delete _debugger;
@@ -126,15 +119,22 @@ void VoyeurEngine::ESP_Init() {
}
void VoyeurEngine::globalInitBolt() {
+ _debugger = new Debugger(this);
+ _eventsManager = new EventsManager(this);
+ _filesManager = new FilesManager(this);
+ _screen = new Screen(this);
+ _soundManager = new SoundManager(_mixer);
+ _voy = new SVoy(this);
+
initBolt();
_filesManager->openBoltLib("bvoy.blt", _bVoy);
_bVoy->getBoltGroup(0x000);
_bVoy->getBoltGroup(0x100);
- _graphicsManager->_fontPtr = &_defaultFontInfo;
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
- assert(_graphicsManager->_fontPtr->_curFont);
+ _screen->_fontPtr = &_defaultFontInfo;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
+ assert(_screen->_fontPtr->_curFont);
// Setup default flags
_voy->_viewBounds = nullptr;
@@ -144,13 +144,13 @@ void VoyeurEngine::globalInitBolt() {
void VoyeurEngine::initBolt() {
vInitInterrupts();
- _graphicsManager->sInitGraphics();
+ _screen->sInitGraphics();
_eventsManager->vInitColor();
initInput();
}
void VoyeurEngine::vInitInterrupts() {
- _eventsManager->_intPtr._palette = &_graphicsManager->_VGAColors[0];
+ _eventsManager->_intPtr._palette = &_screen->_VGAColors[0];
}
void VoyeurEngine::initInput() {
@@ -213,8 +213,8 @@ bool VoyeurEngine::doHeadTitle() {
}
void VoyeurEngine::showConversionScreen() {
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x502)._picResource;
- _graphicsManager->_vPort->setupViewPort();
+ _screen->_backgroundPage = _bVoy->boltEntry(0x502)._picResource;
+ _screen->_vPort->setupViewPort();
flipPageAndWait();
// Immediate palette load to show the initial screen
@@ -237,7 +237,7 @@ void VoyeurEngine::showConversionScreen() {
flipPageAndWaitForFade();
- _graphicsManager->screenReset();
+ _screen->screenReset();
}
bool VoyeurEngine::doLock() {
@@ -249,28 +249,28 @@ bool VoyeurEngine::doLock() {
if (_bVoy->getBoltGroup(0x700)) {
Common::String password = "3333";
- _graphicsManager->_backgroundPage = _bVoy->getPictureResource(0x700);
- _graphicsManager->_backColors = _bVoy->getCMapResource(0x701);
+ _screen->_backgroundPage = _bVoy->getPictureResource(0x700);
+ _screen->_backColors = _bVoy->getCMapResource(0x701);
PictureResource *cursorPic = _bVoy->getPictureResource(0x702);
_voy->_viewBounds = _bVoy->boltEntry(0x704)._rectResource;
Common::Array<RectEntry> &hotspots = _bVoy->boltEntry(0x705)._rectResource->_entries;
assert(cursorPic);
- _graphicsManager->_vPort->setupViewPort();
+ _screen->_vPort->setupViewPort();
- _graphicsManager->_backColors->startFade();
- _graphicsManager->_vPort->_parent->_flags |= DISPFLAG_8;
- _graphicsManager->flipPage();
+ _screen->_backColors->startFade();
+ _screen->_vPort->_parent->_flags |= DISPFLAG_8;
+ _screen->flipPage();
_eventsManager->sWaitFlip();
while (!shouldQuit() && (_eventsManager->_fadeStatus & 1))
_eventsManager->delay(1);
_eventsManager->setCursorColor(127, 0);
- _graphicsManager->setColor(1, 64, 64, 64);
- _graphicsManager->setColor(2, 96, 96, 96);
- _graphicsManager->setColor(3, 160, 160, 160);
- _graphicsManager->setColor(4, 224, 224, 224);
+ _screen->setColor(1, 64, 64, 64);
+ _screen->setColor(2, 96, 96, 96);
+ _screen->setColor(3, 160, 160, 160);
+ _screen->setColor(4, 224, 224, 224);
// Set up the cursor
_eventsManager->setCursor(cursorPic);
@@ -278,9 +278,9 @@ bool VoyeurEngine::doLock() {
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x708)._fontResource;
- _graphicsManager->_fontPtr->_fontSaveBack = 0;
- _graphicsManager->_fontPtr->_fontFlags = DISPFLAG_NONE;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x708)._fontResource;
+ _screen->_fontPtr->_fontSaveBack = 0;
+ _screen->_fontPtr->_fontFlags = DISPFLAG_NONE;
Common::String dateString = "ScummVM";
Common::String displayString = Common::String::format("Last Play %s", dateString.c_str());
@@ -288,16 +288,16 @@ bool VoyeurEngine::doLock() {
bool firstLoop = true;
bool breakFlag = false;
while (!breakFlag && !shouldQuit()) {
- _graphicsManager->_vPort->setupViewPort();
+ _screen->_vPort->setupViewPort();
flipPageAndWait();
// Display the last play time
- _graphicsManager->_fontPtr->_pos = Common::Point(0, 97);
- _graphicsManager->_fontPtr->_justify = ALIGN_CENTER;
- _graphicsManager->_fontPtr->_justifyWidth = 384;
- _graphicsManager->_fontPtr->_justifyHeight = 97;
+ _screen->_fontPtr->_pos = Common::Point(0, 97);
+ _screen->_fontPtr->_justify = ALIGN_CENTER;
+ _screen->_fontPtr->_justifyWidth = 384;
+ _screen->_fontPtr->_justifyHeight = 97;
- _graphicsManager->_vPort->drawText(displayString);
+ _screen->_vPort->drawText(displayString);
flipPageAndWait();
if (firstLoop) {
@@ -356,7 +356,7 @@ bool VoyeurEngine::doLock() {
} else if (key == 11) {
// New code
if ((password.empty() && displayString.empty()) || (password != displayString)) {
- _graphicsManager->_vPort->setupViewPort();
+ _screen->_vPort->setupViewPort();
password = displayString;
displayString = "";
continue;
@@ -373,9 +373,9 @@ bool VoyeurEngine::doLock() {
_soundManager->playVOCMap(wrongVoc, wrongVocSize);
}
- _graphicsManager->fillPic(_graphicsManager->_vPort, 0);
+ _screen->fillPic(_screen->_vPort, 0);
flipPageAndWait();
- _graphicsManager->resetPalette();
+ _screen->resetPalette();
_voy->_viewBounds = nullptr;
_bVoy->freeBoltGroup(0x700);
@@ -393,9 +393,9 @@ void VoyeurEngine::showTitleScreen() {
if (!_bVoy->getBoltGroup(0x500))
return;
- _graphicsManager->_backgroundPage = _bVoy->getPictureResource(0x500);
+ _screen->_backgroundPage = _bVoy->getPictureResource(0x500);
- _graphicsManager->_vPort->setupViewPort();
+ _screen->_vPort->setupViewPort();
flipPageAndWait();
// Immediate palette load to show the initial screen
@@ -422,18 +422,18 @@ void VoyeurEngine::showTitleScreen() {
return;
}
- _graphicsManager->screenReset();
+ _screen->screenReset();
_eventsManager->delayClick(200);
// Voyeur title
playRL2Video("a1100100.rl2");
- _graphicsManager->screenReset();
+ _screen->screenReset();
_bVoy->freeBoltGroup(0x500);
}
void VoyeurEngine::doOpening() {
- _graphicsManager->screenReset();
+ _screen->screenReset();
if (!_bVoy->getBoltGroup(0x200))
return;
@@ -459,10 +459,10 @@ void VoyeurEngine::doOpening() {
_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED;
for (int i = 0; i < 256; ++i)
- _graphicsManager->setColor(i, 8, 8, 8);
+ _screen->setColor(i, 8, 8, 8);
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_vPort->setupViewPort();
+ _screen->_vPort->setupViewPort();
flipPageAndWait();
RL2Decoder decoder;
@@ -472,14 +472,12 @@ void VoyeurEngine::doOpening() {
while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked) {
if (decoder.hasDirtyPalette()) {
const byte *palette = decoder.getPalette();
- _graphicsManager->setPalette(palette, 0, 256);
+ _screen->setPalette(palette, 0, 256);
}
if (decoder.needsUpdate()) {
const Graphics::Surface *frame = decoder.decodeNextFrame();
-
- Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200,
- (byte *)_graphicsManager->_screenSurface.getPixels());
+ _screen->blitFrom(*frame);
if (decoder.getCurFrame() >= (int32)READ_LE_UINT32(frameTable + frameIndex * 4)) {
if (creditShow) {
@@ -499,7 +497,7 @@ void VoyeurEngine::doOpening() {
}
if (textPic) {
- _graphicsManager->sDrawPic(textPic, _graphicsManager->_vPort, textPos);
+ _screen->sDrawPic(textPic, _screen->_vPort, textPos);
}
flipPageAndWait();
@@ -527,14 +525,12 @@ void VoyeurEngine::playRL2Video(const Common::String &filename) {
while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager->_mouseClicked) {
if (decoder.hasDirtyPalette()) {
const byte *palette = decoder.getPalette();
- _graphicsManager->setPalette(palette, 0, 256);
+ _screen->setPalette(palette, 0, 256);
}
if (decoder.needsUpdate()) {
const Graphics::Surface *frame = decoder.decodeNextFrame();
-
- Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200,
- (byte *)_graphicsManager->_screenSurface.getPixels());
+ _screen->blitFrom(*frame);
}
_eventsManager->getMouseInfo();
@@ -573,17 +569,16 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
(decoder.getCurFrame() < endFrame)) {
if (decoder.needsUpdate()) {
const Graphics::Surface *frame = decoder.decodeNextFrame();
+ _screen->blitFrom(*frame);
- Common::copy((const byte *)frame->getPixels(), (const byte *)frame->getPixels() + 320 * 200,
- (byte *)_graphicsManager->_screenSurface.getPixels());
if (_voy->_eventFlags & EVTFLAG_RECORDING)
- _graphicsManager->drawDot();
+ _screen->drawDot();
}
if (decoder.hasDirtyPalette()) {
const byte *palette = decoder.getPalette();
- _graphicsManager->setPalette(palette, 0, decoder.getPaletteCount());
- _graphicsManager->setOneColor(128, 220, 20, 20);
+ _screen->setPalette(palette, 0, decoder.getPaletteCount());
+ _screen->setOneColor(128, 220, 20, 20);
}
_eventsManager->getMouseInfo();
@@ -591,13 +586,13 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
}
// RL2 finished
- _graphicsManager->screenReset();
+ _screen->screenReset();
_voy->_eventFlags &= ~EVTFLAG_RECORDING;
if (_voy->_eventFlags & EVTFLAG_8) {
assert(pic);
- byte *imgData = _graphicsManager->_vPort->_currentPic->_imgData;
- _graphicsManager->_vPort->_currentPic->_imgData = pic->_imgData;
+ byte *imgData = _screen->_vPort->_currentPic->_imgData;
+ _screen->_vPort->_currentPic->_imgData = pic->_imgData;
pic->_imgData = imgData;
_voy->_eventFlags &= ~EVTFLAG_8;
}
@@ -608,13 +603,13 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
void VoyeurEngine::playAudio(int audioId) {
_bVoy->getBoltGroup(0x7F00);
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x7F00 +
+ _screen->_backgroundPage = _bVoy->boltEntry(0x7F00 +
BLIND_TABLE[audioId] * 2)._picResource;
- _graphicsManager->_backColors = _bVoy->boltEntry(0x7F01 +
+ _screen->_backColors = _bVoy->boltEntry(0x7F01 +
BLIND_TABLE[audioId] * 2)._cMapResource;
- _graphicsManager->_vPort->setupViewPort();
- _graphicsManager->_backColors->startFade();
+ _screen->_vPort->setupViewPort();
+ _screen->_backColors->startFade();
flipPageAndWaitForFade();
_voy->_eventFlags &= ~EVTFLAG_TIME_DISABLED;
@@ -633,26 +628,26 @@ void VoyeurEngine::playAudio(int audioId) {
_soundManager->stopVOCPlay();
_bVoy->freeBoltGroup(0x7F00);
- _graphicsManager->_vPort->setupViewPort(NULL);
+ _screen->_vPort->setupViewPort(NULL);
_voy->_eventFlags &= ~EVTFLAG_RECORDING;
_voy->_playStampMode = 129;
}
void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::String &location) {
- _graphicsManager->setColor(128, 16, 16, 16);
- _graphicsManager->setColor(224, 220, 220, 220);
+ _screen->setColor(128, 16, 16, 16);
+ _screen->setColor(224, 220, 220, 220);
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_vPort->setupViewPort(NULL);
- _graphicsManager->_vPort->fillPic(0x80);
- _graphicsManager->flipPage();
+ _screen->_vPort->setupViewPort(NULL);
+ _screen->_vPort->fillPic(0x80);
+ _screen->flipPage();
_eventsManager->sWaitFlip();
flipPageAndWait();
- _graphicsManager->_vPort->fillPic(0x80);
+ _screen->_vPort->fillPic(0x80);
- FontInfoResource &fi = *_graphicsManager->_fontPtr;
+ FontInfoResource &fi = *_screen->_fontPtr;
fi._curFont = _bVoy->boltEntry(257)._fontResource;
fi._foreColor = 224;
fi._fontSaveBack = 0;
@@ -661,7 +656,7 @@ void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::St
fi._justifyWidth = 384;
fi._justifyHeight = 120;
- _graphicsManager->_vPort->drawText(time);
+ _screen->_vPort->drawText(time);
if (!location.empty()) {
fi._pos = Common::Point(0, 138);
@@ -669,7 +664,7 @@ void VoyeurEngine::doTransitionCard(const Common::String &time, const Common::St
fi._justifyWidth = 384;
fi._justifyHeight = 140;
- _graphicsManager->_vPort->drawText(location);
+ _screen->_vPort->drawText(location);
}
flipPageAndWait();
@@ -680,8 +675,8 @@ void VoyeurEngine::saveLastInplay() {
}
void VoyeurEngine::flipPageAndWait() {
- _graphicsManager->_vPort->_flags |= DISPFLAG_8;
- _graphicsManager->flipPage();
+ _screen->_vPort->_flags |= DISPFLAG_8;
+ _screen->flipPage();
_eventsManager->sWaitFlip();
}
@@ -702,7 +697,7 @@ void VoyeurEngine::showEndingNews() {
PictureResource *pic = _bVoy->boltEntry(_playStampGroupId)._picResource;
CMapResource *pal = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource;
- _graphicsManager->_vPort->setupViewPort(pic);
+ _screen->_vPort->setupViewPort(pic);
pal->startFade();
flipPageAndWaitForFade();
@@ -717,7 +712,7 @@ void VoyeurEngine::showEndingNews() {
pal = _bVoy->boltEntry(_playStampGroupId + idx * 2 + 1)._cMapResource;
}
- _graphicsManager->_vPort->setupViewPort(pic);
+ _screen->_vPort->setupViewPort(pic);
pal->startFade();
flipPageAndWaitForFade();
@@ -852,7 +847,7 @@ void VoyeurEngine::synchronize(Common::Serializer &s) {
// Sub-systems
_voy->synchronize(s);
- _graphicsManager->synchronize(s);
+ _screen->synchronize(s);
_mainThread->synchronize(s);
_controlPtr->_state->synchronize(s);
}
@@ -906,8 +901,8 @@ void VoyeurSavegameHeader::write(Common::OutSaveFile *f, VoyeurEngine *vm, const
// Create a thumbnail and save it
Graphics::Surface *thumb = new Graphics::Surface();
- ::createThumbnail(thumb, (byte *)vm->_graphicsManager->_screenSurface.getPixels(),
- SCREEN_WIDTH, SCREEN_HEIGHT, vm->_graphicsManager->_VGAColors);
+ ::createThumbnail(thumb, (const byte *)vm->_screen->getPixels(),
+ SCREEN_WIDTH, SCREEN_HEIGHT, vm->_screen->_VGAColors);
Graphics::saveThumbnail(*f, *thumb);
thumb->free();
delete thumb;
diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h
index e0bb734fa8..9cda85fd51 100644
--- a/engines/voyeur/voyeur.h
+++ b/engines/voyeur/voyeur.h
@@ -27,7 +27,7 @@
#include "voyeur/data.h"
#include "voyeur/events.h"
#include "voyeur/files.h"
-#include "voyeur/graphics.h"
+#include "voyeur/screen.h"
#include "voyeur/sound.h"
#include "common/scummsys.h"
#include "common/system.h"
@@ -164,7 +164,7 @@ public:
Debugger *_debugger;
EventsManager *_eventsManager;
FilesManager *_filesManager;
- GraphicsManager *_graphicsManager;
+ Screen *_screen;
SoundManager *_soundManager;
SVoy *_voy;
diff --git a/engines/voyeur/voyeur_game.cpp b/engines/voyeur/voyeur_game.cpp
index 13ef31839a..e9591955fc 100644
--- a/engines/voyeur/voyeur_game.cpp
+++ b/engines/voyeur/voyeur_game.cpp
@@ -149,8 +149,8 @@ void VoyeurEngine::playStamp() {
case 130: {
// user selected to send the tape
if (_bVoy->getBoltGroup(_playStampGroupId)) {
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(_playStampGroupId)._picResource;
- _graphicsManager->_backColors = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource;
+ _screen->_backgroundPage = _bVoy->boltEntry(_playStampGroupId)._picResource;
+ _screen->_backColors = _bVoy->boltEntry(_playStampGroupId + 1)._cMapResource;
buttonId = getChooseButton();
if (_eventsManager->_rightClick)
@@ -158,7 +158,7 @@ void VoyeurEngine::playStamp() {
buttonId = 4;
_bVoy->freeBoltGroup(_playStampGroupId);
- _graphicsManager->screenReset();
+ _screen->screenReset();
_playStampGroupId = -1;
flag = true;
@@ -232,8 +232,8 @@ void VoyeurEngine::closeStamp() {
}
void VoyeurEngine::doTailTitle() {
- _graphicsManager->_vPort->setupViewPort(NULL);
- _graphicsManager->screenReset();
+ _screen->_vPort->setupViewPort(NULL);
+ _screen->screenReset();
if (_bVoy->getBoltGroup(0x600)) {
RL2Decoder decoder;
@@ -245,12 +245,12 @@ void VoyeurEngine::doTailTitle() {
doClosingCredits();
if (!shouldQuit() && !_eventsManager->_mouseClicked) {
- _graphicsManager->screenReset();
+ _screen->screenReset();
PictureResource *pic = _bVoy->boltEntry(0x602)._picResource;
CMapResource *pal = _bVoy->boltEntry(0x603)._cMapResource;
- _graphicsManager->_vPort->setupViewPort(pic);
+ _screen->_vPort->setupViewPort(pic);
pal->startFade();
flipPageAndWaitForFade();
_eventsManager->delayClick(300);
@@ -258,7 +258,7 @@ void VoyeurEngine::doTailTitle() {
pic = _bVoy->boltEntry(0x604)._picResource;
pal = _bVoy->boltEntry(0x605)._cMapResource;
- _graphicsManager->_vPort->setupViewPort(pic);
+ _screen->_vPort->setupViewPort(pic);
pal->startFade();
flipPageAndWaitForFade();
_eventsManager->delayClick(120);
@@ -283,26 +283,26 @@ void VoyeurEngine::doClosingCredits() {
const char *msg = (const char *)_bVoy->memberAddr(0x404);
const byte *creditList = (const byte *)_bVoy->memberAddr(0x405);
- _graphicsManager->_vPort->setupViewPort(NULL);
- _graphicsManager->setColor(1, 180, 180, 180);
- _graphicsManager->setColor(2, 200, 200, 200);
+ _screen->_vPort->setupViewPort(NULL);
+ _screen->setColor(1, 180, 180, 180);
+ _screen->setColor(2, 200, 200, 200);
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x402)._fontResource;
- _graphicsManager->_fontPtr->_foreColor = 2;
- _graphicsManager->_fontPtr->_backColor = 2;
- _graphicsManager->_fontPtr->_fontSaveBack = false;
- _graphicsManager->_fontPtr->_fontFlags = DISPFLAG_NONE;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x402)._fontResource;
+ _screen->_fontPtr->_foreColor = 2;
+ _screen->_fontPtr->_backColor = 2;
+ _screen->_fontPtr->_fontSaveBack = false;
+ _screen->_fontPtr->_fontFlags = DISPFLAG_NONE;
_soundManager->startVOCPlay(152);
- FontInfoResource &fi = *_graphicsManager->_fontPtr;
+ FontInfoResource &fi = *_screen->_fontPtr;
for (int idx = 0; idx < 78; ++idx) {
const byte *entry = creditList + idx * 6;
int flags = READ_LE_UINT16(entry + 4);
if (flags & 0x10)
- _graphicsManager->_vPort->fillPic(0);
+ _screen->_vPort->fillPic(0);
if (flags & 1) {
fi._foreColor = 1;
@@ -312,7 +312,7 @@ void VoyeurEngine::doClosingCredits() {
fi._justifyHeight = 240;
fi._pos = Common::Point(0, READ_LE_UINT16(entry));
- _graphicsManager->_vPort->drawText(msg);
+ _screen->_vPort->drawText(msg);
msg += strlen(msg) + 1;
}
@@ -324,7 +324,7 @@ void VoyeurEngine::doClosingCredits() {
fi._justifyHeight = 240;
fi._pos = Common::Point(0, READ_LE_UINT16(entry));
- _graphicsManager->_vPort->drawText(msg);
+ _screen->_vPort->drawText(msg);
msg += strlen(msg) + 1;
}
@@ -336,7 +336,7 @@ void VoyeurEngine::doClosingCredits() {
fi._justifyHeight = 240;
fi._pos = Common::Point(38, READ_LE_UINT16(entry));
- _graphicsManager->_vPort->drawText(msg);
+ _screen->_vPort->drawText(msg);
msg += strlen(msg) + 1;
fi._foreColor = 2;
@@ -345,7 +345,7 @@ void VoyeurEngine::doClosingCredits() {
fi._justifyHeight = 240;
fi._pos = Common::Point(198, READ_LE_UINT16(entry));
- _graphicsManager->_vPort->drawText(msg);
+ _screen->_vPort->drawText(msg);
msg += strlen(msg) + 1;
}
@@ -357,7 +357,7 @@ void VoyeurEngine::doClosingCredits() {
fi._justifyHeight = 240;
fi._pos = Common::Point(0, READ_LE_UINT16(entry));
- _graphicsManager->_vPort->drawText(msg);
+ _screen->_vPort->drawText(msg);
msg += strlen(msg) + 1;
fi._foreColor = 2;
@@ -367,7 +367,7 @@ void VoyeurEngine::doClosingCredits() {
fi._justifyHeight = 240;
fi._pos = Common::Point(0, READ_LE_UINT16(entry) + 13);
- _graphicsManager->_vPort->drawText(msg);
+ _screen->_vPort->drawText(msg);
msg += strlen(msg) + 1;
}
@@ -381,19 +381,19 @@ void VoyeurEngine::doClosingCredits() {
}
_soundManager->stopVOCPlay();
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
_bVoy->freeBoltGroup(0x400);
}
void VoyeurEngine::doPiracy() {
- _graphicsManager->screenReset();
- _graphicsManager->setColor(1, 0, 0, 0);
- _graphicsManager->setColor(2, 255, 255, 255);
+ _screen->screenReset();
+ _screen->setColor(1, 0, 0, 0);
+ _screen->setColor(2, 255, 255, 255);
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_vPort->setupViewPort(NULL);
- _graphicsManager->_vPort->fillPic(1);
+ _screen->_vPort->setupViewPort(NULL);
+ _screen->_vPort->fillPic(1);
- FontInfoResource &fi = *_graphicsManager->_fontPtr;
+ FontInfoResource &fi = *_screen->_fontPtr;
fi._curFont = _bVoy->boltEntry(0x101)._fontResource;
fi._foreColor = 2;
fi._backColor = 2;
@@ -406,7 +406,7 @@ void VoyeurEngine::doPiracy() {
// Loop through the piracy message array to draw each line
for (int idx = 0, yp = 33; idx < 10; ++idx) {
fi._pos = Common::Point(0, yp);
- _graphicsManager->_vPort->drawText(PIRACY_MESSAGE[idx]);
+ _screen->_vPort->drawText(PIRACY_MESSAGE[idx]);
yp += fi._curFont->_fontHeight + 4;
}
@@ -439,27 +439,27 @@ void VoyeurEngine::reviewTape() {
_voy->_viewBounds = _bVoy->boltEntry(0x907)._rectResource;
Common::Array<RectEntry> &hotspots = _bVoy->boltEntry(0x906)._rectResource->_entries;
- _graphicsManager->_backColors = _bVoy->boltEntry(0x902)._cMapResource;
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x901)._picResource;
- _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage);
- _graphicsManager->_backColors->startFade();
+ _screen->_backColors = _bVoy->boltEntry(0x902)._cMapResource;
+ _screen->_backgroundPage = _bVoy->boltEntry(0x901)._picResource;
+ _screen->_vPort->setupViewPort(_screen->_backgroundPage);
+ _screen->_backColors->startFade();
flipPageAndWaitForFade();
- _graphicsManager->setColor(1, 32, 32, 32);
- _graphicsManager->setColor(2, 96, 96, 96);
- _graphicsManager->setColor(3, 160, 160, 160);
- _graphicsManager->setColor(4, 224, 224, 224);
- _graphicsManager->setColor(9, 24, 64, 24);
- _graphicsManager->setColor(10, 64, 132, 64);
- _graphicsManager->setColor(11, 100, 192, 100);
- _graphicsManager->setColor(12, 120, 248, 120);
+ _screen->setColor(1, 32, 32, 32);
+ _screen->setColor(2, 96, 96, 96);
+ _screen->setColor(3, 160, 160, 160);
+ _screen->setColor(4, 224, 224, 224);
+ _screen->setColor(9, 24, 64, 24);
+ _screen->setColor(10, 64, 132, 64);
+ _screen->setColor(11, 100, 192, 100);
+ _screen->setColor(12, 120, 248, 120);
_eventsManager->setCursorColor(128, 1);
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x909)._fontResource;
- _graphicsManager->_fontPtr->_fontSaveBack = false;
- _graphicsManager->_fontPtr->_fontFlags = DISPFLAG_NONE;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x909)._fontResource;
+ _screen->_fontPtr->_fontSaveBack = false;
+ _screen->_fontPtr->_fontFlags = DISPFLAG_NONE;
_eventsManager->getMouseInfo();
if (newX == -1) {
@@ -481,37 +481,37 @@ void VoyeurEngine::reviewTape() {
needRedraw = false;
flipPageAndWait();
- _graphicsManager->_drawPtr->_penColor = 0;
- _graphicsManager->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top);
- _graphicsManager->_backgroundPage->sFillBox(tempRect.width(), tempRect.height());
+ _screen->_drawPtr->_penColor = 0;
+ _screen->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top);
+ _screen->_backgroundPage->sFillBox(tempRect.width(), tempRect.height());
int yp = 45;
int eventNum = eventStart;
for (int lineNum = 0; lineNum < 8 && eventNum < _voy->_eventCount; ++lineNum, ++eventNum) {
- _graphicsManager->_fontPtr->_picFlags = DISPFLAG_NONE;
- _graphicsManager->_fontPtr->_picSelect = 0xff;
- _graphicsManager->_fontPtr->_picPick = 7;
- _graphicsManager->_fontPtr->_picOnOff = (lineNum == eventLine) ? 8 : 0;
- _graphicsManager->_fontPtr->_pos = Common::Point(68, yp);
- _graphicsManager->_fontPtr->_justify = ALIGN_LEFT;
- _graphicsManager->_fontPtr->_justifyWidth = 0;
- _graphicsManager->_fontPtr->_justifyHeight = 0;
+ _screen->_fontPtr->_picFlags = DISPFLAG_NONE;
+ _screen->_fontPtr->_picSelect = 0xff;
+ _screen->_fontPtr->_picPick = 7;
+ _screen->_fontPtr->_picOnOff = (lineNum == eventLine) ? 8 : 0;
+ _screen->_fontPtr->_pos = Common::Point(68, yp);
+ _screen->_fontPtr->_justify = ALIGN_LEFT;
+ _screen->_fontPtr->_justifyWidth = 0;
+ _screen->_fontPtr->_justifyHeight = 0;
Common::String msg = _eventsManager->getEvidString(eventNum);
- _graphicsManager->_backgroundPage->drawText(msg);
+ _screen->_backgroundPage->drawText(msg);
yp += 15;
}
- _graphicsManager->_vPort->addSaveRect(
- _graphicsManager->_vPort->_lastPage, tempRect);
+ _screen->_vPort->addSaveRect(
+ _screen->_vPort->_lastPage, tempRect);
flipPageAndWait();
- _graphicsManager->_vPort->addSaveRect(
- _graphicsManager->_vPort->_lastPage, tempRect);
+ _screen->_vPort->addSaveRect(
+ _screen->_vPort->_lastPage, tempRect);
}
- _graphicsManager->sDrawPic(cursor, _graphicsManager->_vPort,
+ _screen->sDrawPic(cursor, _screen->_vPort,
_eventsManager->getMousePos());
flipPageAndWait();
@@ -543,34 +543,34 @@ void VoyeurEngine::reviewTape() {
flipPageAndWait();
- _graphicsManager->_drawPtr->_penColor = 0;
- _graphicsManager->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top);
- _graphicsManager->_backgroundPage->sFillBox(tempRect.width(), tempRect.height());
+ _screen->_drawPtr->_penColor = 0;
+ _screen->_drawPtr->_pos = Common::Point(tempRect.left, tempRect.top);
+ _screen->_backgroundPage->sFillBox(tempRect.width(), tempRect.height());
int yp = 45;
int eventNum = eventStart;
for (int idx = 0; idx < 8 && eventNum < _voy->_eventCount; ++idx, ++eventNum) {
- _graphicsManager->_fontPtr->_picFlags = DISPFLAG_NONE;
- _graphicsManager->_fontPtr->_picSelect = 0xff;
- _graphicsManager->_fontPtr->_picPick = 7;
- _graphicsManager->_fontPtr->_picOnOff = (idx == eventLine) ? 8 : 0;
- _graphicsManager->_fontPtr->_pos = Common::Point(68, yp);
- _graphicsManager->_fontPtr->_justify = ALIGN_LEFT;
- _graphicsManager->_fontPtr->_justifyWidth = 0;
- _graphicsManager->_fontPtr->_justifyHeight = 0;
+ _screen->_fontPtr->_picFlags = DISPFLAG_NONE;
+ _screen->_fontPtr->_picSelect = 0xff;
+ _screen->_fontPtr->_picPick = 7;
+ _screen->_fontPtr->_picOnOff = (idx == eventLine) ? 8 : 0;
+ _screen->_fontPtr->_pos = Common::Point(68, yp);
+ _screen->_fontPtr->_justify = ALIGN_LEFT;
+ _screen->_fontPtr->_justifyWidth = 0;
+ _screen->_fontPtr->_justifyHeight = 0;
Common::String msg = _eventsManager->getEvidString(eventNum);
- _graphicsManager->_backgroundPage->drawText(msg);
+ _screen->_backgroundPage->drawText(msg);
yp += 15;
}
- _graphicsManager->_vPort->addSaveRect(
- _graphicsManager->_vPort->_lastPage, tempRect);
+ _screen->_vPort->addSaveRect(
+ _screen->_vPort->_lastPage, tempRect);
flipPageAndWait();
- _graphicsManager->_vPort->addSaveRect(
- _graphicsManager->_vPort->_lastPage, tempRect);
+ _screen->_vPort->addSaveRect(
+ _screen->_vPort->_lastPage, tempRect);
flipPageAndWait();
_eventsManager->getMouseInfo();
@@ -650,7 +650,7 @@ void VoyeurEngine::reviewTape() {
newY = _eventsManager->getMousePos().y;
_voy->_fadingType = 0;
_voy->_viewBounds = nullptr;
- _graphicsManager->_vPort->setupViewPort(NULL);
+ _screen->_vPort->setupViewPort(NULL);
if (_currentVocId != -1) {
_voy->_vocSecondsOffset = _voy->_RTVNum - _voy->_musicStartTime;
@@ -673,13 +673,13 @@ void VoyeurEngine::reviewTape() {
_voy->_vocSecondsOffset = e._computerOn;
_bVoy->getBoltGroup(0x7F00);
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x7F00 +
+ _screen->_backgroundPage = _bVoy->boltEntry(0x7F00 +
BLIND_TABLE[_audioVideoId])._picResource;
- _graphicsManager->_backColors = _bVoy->boltEntry(0x7F01 +
+ _screen->_backColors = _bVoy->boltEntry(0x7F01 +
BLIND_TABLE[_audioVideoId])._cMapResource;
- _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage);
- _graphicsManager->_backColors->startFade();
+ _screen->_vPort->setupViewPort(_screen->_backgroundPage);
+ _screen->_backColors->startFade();
flipPageAndWaitForFade();
_eventsManager->_intPtr._flashStep = 1;
@@ -725,16 +725,16 @@ void VoyeurEngine::reviewTape() {
}
}
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
- _graphicsManager->_vPort->fillPic(0);
+ _screen->_vPort->fillPic(0);
flipPageAndWait();
_bVoy->freeBoltGroup(0x900);
}
void VoyeurEngine::doGossip() {
- _graphicsManager->resetPalette();
- _graphicsManager->screenReset();
+ _screen->resetPalette();
+ _screen->screenReset();
if (!_bVoy->getBoltGroup(0x300))
return;
@@ -752,7 +752,7 @@ void VoyeurEngine::doGossip() {
// Transfer initial background to video decoder
PictureResource videoFrame(decoder.getRL2VideoTrack()->getBackSurface());
bgPic->_bounds.moveTo(0, 0);
- _graphicsManager->sDrawPic(bgPic, &videoFrame, Common::Point(0, 0));
+ _screen->sDrawPic(bgPic, &videoFrame, Common::Point(0, 0));
byte *frameNumsP = _bVoy->memberAddr(0x309);
byte *posP = _bVoy->boltEntry(0x30A)._data;
@@ -762,8 +762,8 @@ void VoyeurEngine::doGossip() {
decoder.close();
// Reset the palette and clear the screen
- _graphicsManager->resetPalette();
- _graphicsManager->screenReset();
+ _screen->resetPalette();
+ _screen->screenReset();
// Play interview video
RL2Decoder decoder2;
@@ -775,7 +775,7 @@ void VoyeurEngine::doGossip() {
decoder2.close();
_bVoy->freeBoltGroup(0x300);
- _graphicsManager->screenReset();
+ _screen->screenReset();
}
void VoyeurEngine::doTapePlaying() {
@@ -783,14 +783,14 @@ void VoyeurEngine::doTapePlaying() {
return;
_eventsManager->getMouseInfo();
- _graphicsManager->_backColors = _bVoy->boltEntry(0xA01)._cMapResource;
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(0xA00)._picResource;
+ _screen->_backColors = _bVoy->boltEntry(0xA01)._cMapResource;
+ _screen->_backgroundPage = _bVoy->boltEntry(0xA00)._picResource;
PictureResource *pic = _bVoy->boltEntry(0xA02)._picResource;
VInitCycleResource *cycle = _bVoy->boltEntry(0xA05)._vInitCycleResource;
- _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage);
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(57, 30));
- _graphicsManager->_backColors->startFade();
+ _screen->_vPort->setupViewPort(_screen->_backgroundPage);
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(57, 30));
+ _screen->_backColors->startFade();
flipPageAndWaitForFade();
cycle->vStartCycle();
@@ -932,9 +932,9 @@ int VoyeurEngine::getChooseButton() {
+ 6)._rectResource->_entries;
int selectedIndex = -1;
- _graphicsManager->_vPort->setupViewPort(_graphicsManager->_backgroundPage);
- _graphicsManager->_backColors->_steps = 0;
- _graphicsManager->_backColors->startFade();
+ _screen->_vPort->setupViewPort(_screen->_backgroundPage);
+ _screen->_backColors->_steps = 0;
+ _screen->_backColors->startFade();
flipPageAndWait();
_voy->_viewBounds = _bVoy->boltEntry(_playStampGroupId + 7)._rectResource;
@@ -955,7 +955,7 @@ int VoyeurEngine::getChooseButton() {
selectedIndex = idx;
if (selectedIndex != prevIndex) {
PictureResource *btnPic = _bVoy->boltEntry(_playStampGroupId + 8 + idx)._picResource;
- _graphicsManager->sDrawPic(btnPic, _graphicsManager->_vPort,
+ _screen->sDrawPic(btnPic, _screen->_vPort,
Common::Point(106, 200));
cursorPic = _bVoy->boltEntry(_playStampGroupId + 4)._picResource;
@@ -967,11 +967,11 @@ int VoyeurEngine::getChooseButton() {
if (selectedIndex == -1) {
cursorPic = _bVoy->boltEntry(_playStampGroupId + 2)._picResource;
PictureResource *btnPic = _bVoy->boltEntry(_playStampGroupId + 12)._picResource;
- _graphicsManager->sDrawPic(btnPic, _graphicsManager->_vPort,
+ _screen->sDrawPic(btnPic, _screen->_vPort,
Common::Point(106, 200));
}
- _graphicsManager->sDrawPic(cursorPic, _graphicsManager->_vPort,
+ _screen->sDrawPic(cursorPic, _screen->_vPort,
Common::Point(pt.x + 13, pt.y - 12));
flipPageAndWait();
@@ -982,9 +982,9 @@ int VoyeurEngine::getChooseButton() {
}
void VoyeurEngine::makeViewFinder() {
- _graphicsManager->_backgroundPage = _bVoy->boltEntry(0x103)._picResource;
- _graphicsManager->sDrawPic(_graphicsManager->_backgroundPage,
- _graphicsManager->_vPort, Common::Point(0, 0));
+ _screen->_backgroundPage = _bVoy->boltEntry(0x103)._picResource;
+ _screen->sDrawPic(_screen->_backgroundPage,
+ _screen->_vPort, Common::Point(0, 0));
CMapResource *pal = _bVoy->boltEntry(0x104)._cMapResource;
int palOffset = 0;
@@ -1016,22 +1016,22 @@ void VoyeurEngine::makeViewFinder() {
break;
}
- _graphicsManager->_vPort->drawIfaceTime();
+ _screen->_vPort->drawIfaceTime();
doTimeBar();
pal->startFade();
flipPageAndWaitForFade();
- _graphicsManager->setColor(241, 105, 105, 105);
- _graphicsManager->setColor(242, 105, 105, 105);
- _graphicsManager->setColor(243, 105, 105, 105);
- _graphicsManager->setColor(palOffset + 241, 219, 235, 235);
+ _screen->setColor(241, 105, 105, 105);
+ _screen->setColor(242, 105, 105, 105);
+ _screen->setColor(243, 105, 105, 105);
+ _screen->setColor(palOffset + 241, 219, 235, 235);
_eventsManager->_intPtr._hasPalette = true;
}
void VoyeurEngine::makeViewFinderP() {
- _graphicsManager->screenReset();
+ _screen->screenReset();
}
void VoyeurEngine::initIFace() {
@@ -1077,7 +1077,7 @@ void VoyeurEngine::initIFace() {
void VoyeurEngine::doScroll(const Common::Point &pt) {
Common::Rect clipRect(72, 47, 72 + 240, 47 + 148);
- _graphicsManager->_vPort->setupViewPort(NULL, &clipRect);
+ _screen->_vPort->setupViewPort(NULL, &clipRect);
int base = 0;
switch (_voy->_transitionId) {
@@ -1101,18 +1101,18 @@ void VoyeurEngine::doScroll(const Common::Point &pt) {
if (base) {
PictureResource *pic = _bVoy->boltEntry(base + 3)._picResource;
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 104));
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 104));
pic = _bVoy->boltEntry(base + 4)._picResource;
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 44));
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y - 44));
pic = _bVoy->boltEntry(base + 5)._picResource;
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 16));
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 16));
pic = _bVoy->boltEntry(base + 6)._picResource;
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 76));
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 76));
pic = _bVoy->boltEntry(base + 7)._picResource;
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 136));
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(784 - pt.x - 712, 150 - pt.y + 136));
}
- _graphicsManager->_vPort->setupViewPort(NULL);
+ _screen->_vPort->setupViewPort(NULL);
}
void VoyeurEngine::checkTransition() {
@@ -1124,7 +1124,7 @@ void VoyeurEngine::checkTransition() {
// Only proceed if a valid day string was returned
if (!day.empty()) {
- _graphicsManager->fadeDownICF(6);
+ _screen->fadeDownICF(6);
// Get the time of day string
time = getTimeOfDay();
@@ -1163,7 +1163,7 @@ Common::String VoyeurEngine::getTimeOfDay() {
}
int VoyeurEngine::doComputerText(int maxLen) {
- FontInfoResource &font = *_graphicsManager->_fontPtr;
+ FontInfoResource &font = *_screen->_fontPtr;
int totalChars = 0;
font._curFont = _bVoy->boltEntry(0x4910)._fontResource;
@@ -1180,7 +1180,7 @@ int VoyeurEngine::doComputerText(int maxLen) {
font._justifyWidth = 384;
font._justifyHeight = 100;
font._pos = Common::Point(128, 100);
- _graphicsManager->_vPort->drawText(END_OF_MESSAGE);
+ _screen->_vPort->drawText(END_OF_MESSAGE);
} else if (_voy->_RTVNum < _voy->_computerTimeMin && maxLen == 9999) {
if (_currentVocId != -1)
_soundManager->startVOCPlay(_currentVocId);
@@ -1188,7 +1188,7 @@ int VoyeurEngine::doComputerText(int maxLen) {
font._justifyWidth = 384;
font._justifyHeight = 100;
font._pos = Common::Point(120, 100);
- _graphicsManager->_vPort->drawText(START_OF_MESSAGE);
+ _screen->_vPort->drawText(START_OF_MESSAGE);
} else {
char *msg = (char *)_bVoy->memberAddr(0x4900 + _voy->_computerTextId);
font._pos = Common::Point(96, 60);
@@ -1206,14 +1206,14 @@ int VoyeurEngine::doComputerText(int maxLen) {
if (c == '\0') {
if (showEnd) {
_eventsManager->delay(90);
- _graphicsManager->_drawPtr->_pos = Common::Point(96, 54);
- _graphicsManager->_drawPtr->_penColor = 254;
- _graphicsManager->_vPort->sFillBox(196, 124);
- _graphicsManager->_fontPtr->_justify = ALIGN_LEFT;
- _graphicsManager->_fontPtr->_justifyWidth = 384;
- _graphicsManager->_fontPtr->_justifyHeight = 100;
- _graphicsManager->_fontPtr->_pos = Common::Point(128, 100);
- _graphicsManager->_vPort->drawText(END_OF_MESSAGE);
+ _screen->_drawPtr->_pos = Common::Point(96, 54);
+ _screen->_drawPtr->_penColor = 254;
+ _screen->_vPort->sFillBox(196, 124);
+ _screen->_fontPtr->_justify = ALIGN_LEFT;
+ _screen->_fontPtr->_justifyWidth = 384;
+ _screen->_fontPtr->_justifyHeight = 100;
+ _screen->_fontPtr->_pos = Common::Point(128, 100);
+ _screen->_vPort->drawText(END_OF_MESSAGE);
}
break;
}
@@ -1223,20 +1223,20 @@ int VoyeurEngine::doComputerText(int maxLen) {
yp += 10;
} else {
_eventsManager->delay(90);
- _graphicsManager->_drawPtr->_pos = Common::Point(96, 54);
- _graphicsManager->_drawPtr->_penColor = 255;
- _graphicsManager->_vPort->sFillBox(196, 124);
+ _screen->_drawPtr->_pos = Common::Point(96, 54);
+ _screen->_drawPtr->_penColor = 255;
+ _screen->_vPort->sFillBox(196, 124);
yp = 60;
}
- _graphicsManager->_fontPtr->_pos = Common::Point(96, yp);
+ _screen->_fontPtr->_pos = Common::Point(96, yp);
} else if (c == '_') {
showEnd = false;
} else {
- _graphicsManager->_fontPtr->_justify = ALIGN_LEFT;
- _graphicsManager->_fontPtr->_justifyWidth = 0;
- _graphicsManager->_fontPtr->_justifyHeight = 0;
- _graphicsManager->_vPort->drawText(Common::String(c));
+ _screen->_fontPtr->_justify = ALIGN_LEFT;
+ _screen->_fontPtr->_justifyWidth = 0;
+ _screen->_fontPtr->_justifyHeight = 0;
+ _screen->_vPort->drawText(Common::String(c));
_eventsManager->delay(4);
}
@@ -1251,7 +1251,7 @@ int VoyeurEngine::doComputerText(int maxLen) {
flipPageAndWait();
- _graphicsManager->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
+ _screen->_fontPtr->_curFont = _bVoy->boltEntry(0x101)._fontResource;
return totalChars;
}
@@ -1263,7 +1263,7 @@ void VoyeurEngine::getComputerBrush() {
int xp = (384 - pic->_bounds.width()) / 2;
int yp = (240 - pic->_bounds.height()) / 2 - 4;
- _graphicsManager->_vPort->drawPicPerm(pic, Common::Point(xp, yp));
+ _screen->_vPort->drawPicPerm(pic, Common::Point(xp, yp));
CMapResource *pal = _bVoy->boltEntry(0x490F)._cMapResource;
pal->startFade();
@@ -1280,17 +1280,17 @@ void VoyeurEngine::doTimeBar() {
int height = ((_voy->_RTVLimit - _voy->_RTVNum) * 59) / _voy->_RTVLimit;
int fullHeight = MAX(151 - height, 93);
- _graphicsManager->_drawPtr->_penColor = 134;
- _graphicsManager->_drawPtr->_pos = Common::Point(39, 92);
+ _screen->_drawPtr->_penColor = 134;
+ _screen->_drawPtr->_pos = Common::Point(39, 92);
- _graphicsManager->_vPort->sFillBox(6, fullHeight - 92);
+ _screen->_vPort->sFillBox(6, fullHeight - 92);
if (height > 0) {
- _graphicsManager->setColor(215, 238, 238, 238);
+ _screen->setColor(215, 238, 238, 238);
_eventsManager->_intPtr._hasPalette = true;
- _graphicsManager->_drawPtr->_penColor = 215;
- _graphicsManager->_drawPtr->_pos = Common::Point(39, fullHeight);
- _graphicsManager->_vPort->sFillBox(6, height);
+ _screen->_drawPtr->_penColor = 215;
+ _screen->_drawPtr->_pos = Common::Point(39, fullHeight);
+ _screen->_vPort->sFillBox(6, height);
}
}
}
@@ -1303,9 +1303,9 @@ void VoyeurEngine::flashTimeBar() {
_flashTimeVal = _eventsManager->_intPtr._flashTimer;
if (_flashTimeFlag)
- _graphicsManager->setColor(240, 220, 20, 20);
+ _screen->setColor(240, 220, 20, 20);
else
- _graphicsManager->setColor(240, 220, 220, 220);
+ _screen->setColor(240, 220, 220, 220);
_eventsManager->_intPtr._hasPalette = true;
_flashTimeFlag = !_flashTimeFlag;
@@ -1343,7 +1343,7 @@ void VoyeurEngine::doEvidDisplay(int evidId, int eventId) {
_bVoy->getBoltGroup(_voy->_boltGroupId2);
PictureResource *pic = _bVoy->boltEntry(_voy->_boltGroupId2 + evidId * 2)._picResource;
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort, Common::Point(
+ _screen->sDrawPic(pic, _screen->_vPort, Common::Point(
(384 - pic->_bounds.width()) / 2, (240 - pic->_bounds.height()) / 2));
_bVoy->freeBoltMember(_voy->_boltGroupId2 + evidId * 2);
@@ -1394,7 +1394,7 @@ void VoyeurEngine::doEvidDisplay(int evidId, int eventId) {
continue;
pic = _voy->_evPicPtrs[arrIndex];
- _graphicsManager->sDrawPic(pic, _graphicsManager->_vPort,
+ _screen->sDrawPic(pic, _screen->_vPort,
Common::Point((384 - pic->_bounds.width()) / 2,
(240 - pic->_bounds.height()) / 2));
_voy->_evCmPtrs[arrIndex]->startFade();
diff --git a/engines/wage/debugger.cpp b/engines/wage/debugger.cpp
new file mode 100644
index 0000000000..d34aca7d49
--- /dev/null
+++ b/engines/wage/debugger.cpp
@@ -0,0 +1,97 @@
+/* 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.
+ *
+ */
+
+#include "common/file.h"
+#include "wage/wage.h"
+#include "wage/debugger.h"
+#include "wage/entities.h"
+#include "wage/script.h"
+#include "wage/world.h"
+
+namespace Wage {
+
+Debugger::Debugger(WageEngine *engine) : GUI::Debugger(), _engine(engine) {
+ registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
+ registerCmd("scenes", WRAP_METHOD(Debugger, Cmd_ListScenes));
+ registerCmd("script", WRAP_METHOD(Debugger, Cmd_Script));
+}
+
+Debugger::~Debugger() {
+}
+
+static int strToInt(const char *s) {
+ if (!*s)
+ // No string at all
+ return 0;
+ else if (toupper(s[strlen(s) - 1]) != 'H')
+ // Standard decimal string
+ return atoi(s);
+
+ // Hexadecimal string
+ uint tmp = 0;
+ int read = sscanf(s, "%xh", &tmp);
+
+ if (read < 1)
+ error("strToInt failed on string \"%s\"", s);
+ return (int)tmp;
+}
+
+bool Debugger::Cmd_ListScenes(int argc, const char **argv) {
+ int currentScene = 0;
+
+ for (uint i = 1; i < _engine->_world->_orderedScenes.size(); i++) { // #0 is STORAGE@
+ if (_engine->_world->_player->_currentScene == _engine->_world->_orderedScenes[i])
+ currentScene = i;
+
+ debugPrintf("%d: %s\n", i, _engine->_world->_orderedScenes[i]->_name.c_str());
+ }
+
+ debugPrintf("\nCurrent scene is #%d: %s\n", currentScene, _engine->_world->_orderedScenes[currentScene]->_name.c_str());
+
+ return true;
+}
+
+bool Debugger::Cmd_Script(int argc, const char **argv) {
+ Script *script = _engine->_world->_player->_currentScene->_script;
+
+ if (argc >= 2) {
+ int scriptNum = strToInt(argv[1]);
+
+ if (scriptNum)
+ script = _engine->_world->_orderedScenes[scriptNum]->_script;
+ else
+ script = _engine->_world->_globalScript;
+ }
+
+ if (script == NULL) {
+ debugPrintf("There is no script for current scene\n");
+ return true;
+ }
+
+ for (uint i = 0; i < script->_scriptText.size(); i++) {
+ debugPrintf("%d [%04x]: %s\n", i, script->_scriptText[i]->offset, script->_scriptText[i]->line.c_str());
+ }
+
+ return true;
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/debugger.h b/engines/wage/debugger.h
new file mode 100644
index 0000000000..90687760cb
--- /dev/null
+++ b/engines/wage/debugger.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+#ifndef WAGE_DEBUGGER_H
+#define WAGE_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Wage {
+
+class WageEngine;
+
+class Debugger : public GUI::Debugger {
+protected:
+ WageEngine *_engine;
+
+ bool Cmd_ListScenes(int argc, const char **argv);
+ bool Cmd_Script(int argc, const char **argv);
+
+public:
+ Debugger(WageEngine *engine);
+ virtual ~Debugger();
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/design.cpp b/engines/wage/design.cpp
index 2a63436f5a..2bfea9df7d 100644
--- a/engines/wage/design.cpp
+++ b/engines/wage/design.cpp
@@ -45,20 +45,23 @@
*
*/
+#include "graphics/managed_surface.h"
#include "graphics/primitives.h"
-#include "wage/wage.h"
+
+#include "wage/macwindowmanager.h"
#include "wage/design.h"
namespace Wage {
struct PlotData {
- Graphics::Surface *surface;
+ Graphics::ManagedSurface *surface;
Patterns *patterns;
uint fillType;
int thickness;
+ Design *design;
- PlotData(Graphics::Surface *s, Patterns *p, int f, int t) :
- surface(s), patterns(p), fillType(f), thickness(t) {}
+ PlotData(Graphics::ManagedSurface *s, Patterns *p, int f, int t, Design *d) :
+ surface(s), patterns(p), fillType(f), thickness(t), design(d) {}
};
void drawPixel(int x, int y, int color, void *data);
@@ -71,6 +74,8 @@ Design::Design(Common::SeekableReadStream *data) {
_surface = NULL;
_bounds = NULL;
+
+ _boundsCalculationMode = false;
}
Design::~Design() {
@@ -80,21 +85,30 @@ Design::~Design() {
delete _surface;
}
-void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y) {
- Common::MemoryReadStream in(_data, _len);
- Common::Rect r(0, 0, _bounds->width(), _bounds->height());
+void Design::paint(Graphics::ManagedSurface *surface, Patterns &patterns, int x, int y) {
bool needRender = false;
if (_surface == NULL) {
- _surface = new Graphics::Surface;
+ _boundsCalculationMode = true;
+ _bounds->debugPrint(4, "Internal bounds:");
+ render(patterns);
+ _boundsCalculationMode = false;
+ if (_bounds->right == -10000) {
+ _bounds->left = _bounds->top = _bounds->right = _bounds->bottom = 0;
+ }
+ _bounds->debugPrint(4, "Calculated bounds:");
+
+ _surface = new Graphics::ManagedSurface;
_surface->create(_bounds->width(), _bounds->height(), Graphics::PixelFormat::createFormatCLUT8());
- _surface->fillRect(r, kColorGreen);
+
+ _surface->clear(kColorGreen);
needRender = true;
}
+ _bounds->debugPrint(4, "Using bounds:");
#if 0
- PlotData pd(_surface, &patterns, 8, 1);
+ PlotData pd(_surface, &patterns, 8, 1, this);
int x1 = 50, y1 = 50, x2 = 200, y2 = 200, borderThickness = 30;
Common::Rect inn(x1-5, y1-5, x2+5, y2+5);
drawRoundRect(inn, 6, kColorGray, false, drawPixelPlain, &pd);
@@ -115,6 +129,22 @@ void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y)
return;
#endif
+ if (needRender)
+ render(patterns);
+
+ if (_bounds->width() && _bounds->height()) {
+ const int padding = 3;
+ Common::Rect from(padding, padding, _bounds->width() - 2 * padding, _bounds->height() - 2 * padding);
+ Common::Rect to(from);
+ to.moveTo(x, y);
+ surface->transBlitFrom(*_surface, from, to, kColorGreen);
+ }
+}
+
+void Design::render(Patterns &patterns) {
+ Common::MemoryReadStream in(_data, _len);
+ bool needRender = true;
+
while (needRender) {
byte fillType = in.readByte();
byte borderThickness = in.readByte();
@@ -152,18 +182,6 @@ void Design::paint(Graphics::Surface *surface, Patterns &patterns, int x, int y)
//g_system->updateScreen();
//g_system->delayMillis(500);
}
-
- const int padding = 3;
- for (int i = padding; i < _bounds->height() - 2 * padding; i++) {
- const byte *src = (const byte *)_surface->getBasePtr(padding, i);
- byte *dst = (byte *)surface->getBasePtr(x + padding, y+i);
- for (int j = padding; j < _bounds->width() - 2 * padding; j++) {
- if (*src != kColorGreen)
- *dst = *src;
- src++;
- dst++;
- }
- }
}
bool Design::isPointOpaque(int x, int y) {
@@ -175,26 +193,51 @@ bool Design::isPointOpaque(int x, int y) {
return pixel != kColorGreen;
}
+void Design::adjustBounds(int16 x, int16 y) {
+ _bounds->right = MAX(x, _bounds->right);
+ _bounds->bottom = MAX(y, _bounds->bottom);
+}
+
void drawPixel(int x, int y, int color, void *data) {
PlotData *p = (PlotData *)data;
if (p->fillType > p->patterns->size())
return;
+ if (p->design && p->design->isBoundsCalculation()) {
+ if (x < 0 || y < 0)
+ return;
+ if (p->thickness == 1) {
+ p->design->adjustBounds(x, y);
+ } else {
+ int x1 = x;
+ int x2 = x1 + p->thickness;
+ int y1 = y;
+ int y2 = y1 + p->thickness;
+
+ for (y = y1; y < y2; y++)
+ for (x = x1; x < x2; x++)
+ p->design->adjustBounds(x, y);
+ }
+
+ return;
+ }
+
byte *pat = p->patterns->operator[](p->fillType - 1);
if (p->thickness == 1) {
if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
uint xu = (uint)x; // for letting compiler optimize it
uint yu = (uint)y;
+
*((byte *)p->surface->getBasePtr(xu, yu)) =
(pat[yu % 8] & (1 << (7 - xu % 8))) ?
color : kColorWhite;
}
} else {
- int x1 = x - p->thickness / 2;
+ int x1 = x;
int x2 = x1 + p->thickness;
- int y1 = y - p->thickness / 2;
+ int y1 = y;
int y2 = y1 + p->thickness;
for (y = y1; y < y2; y++)
@@ -212,11 +255,16 @@ void drawPixel(int x, int y, int color, void *data) {
void drawPixelPlain(int x, int y, int color, void *data) {
PlotData *p = (PlotData *)data;
+ if (p->design && p->design->isBoundsCalculation()) {
+ p->design->adjustBounds(x, y);
+ return;
+ }
+
if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h)
*((byte *)p->surface->getBasePtr(x, y)) = (byte)color;
}
-void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
int16 y1 = in.readSint16BE();
int16 x1 = in.readSint16BE();
@@ -229,7 +277,7 @@ void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in,
SWAP(y1, y2);
Common::Rect r(x1, y1, x2, y2);
- PlotData pd(surface, &patterns, fillType, 1);
+ PlotData pd(surface, &patterns, fillType, 1, this);
if (fillType <= patterns.size())
Graphics::drawFilledRect(r, kColorBlack, drawPixel, &pd);
@@ -245,7 +293,7 @@ void Design::drawRect(Graphics::Surface *surface, Common::ReadStream &in,
}
}
-void Design::drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawRoundRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
int16 y1 = in.readSint16BE();
int16 x1 = in.readSint16BE();
@@ -259,19 +307,19 @@ void Design::drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in,
SWAP(y1, y2);
Common::Rect r(x1, y1, x2, y2);
- PlotData pd(surface, &patterns, fillType, 1);
+ PlotData pd(surface, &patterns, fillType, 1, this);
if (fillType <= patterns.size())
- Graphics::drawRoundRect(r, arc/2, kColorBlack, true, drawPixel, &pd);
+ Graphics::drawRoundRect(r, arc / 2, kColorBlack, true, drawPixel, &pd);
pd.fillType = borderFillType;
pd.thickness = borderThickness;
if (borderThickness > 0 && borderFillType <= patterns.size())
- Graphics::drawRoundRect(r, arc/2, kColorBlack, false, drawPixel, &pd);
+ Graphics::drawRoundRect(r, arc / 2, kColorBlack, false, drawPixel, &pd);
}
-void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawPolygon(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
byte ignored = in.readSint16BE(); // ignored
@@ -331,7 +379,7 @@ void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
ypoints[i] = ycoords[i];
}
- PlotData pd(surface, &patterns, fillType, 1);
+ PlotData pd(surface, &patterns, fillType, 1, this);
if (fillType <= patterns.size()) {
Graphics::drawPolygonScan(xpoints, ypoints, npoints, bbox, kColorBlack, drawPixel, &pd);
@@ -348,13 +396,13 @@ void Design::drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
free(ypoints);
}
-void Design::drawOval(Graphics::Surface *surface, Common::ReadStream &in,
+void Design::drawOval(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType) {
int16 y1 = in.readSint16BE();
int16 x1 = in.readSint16BE();
int16 y2 = in.readSint16BE();
int16 x2 = in.readSint16BE();
- PlotData pd(surface, &patterns, fillType, 1);
+ PlotData pd(surface, &patterns, fillType, 1, this);
if (fillType <= patterns.size())
Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, true, drawPixel, &pd);
@@ -366,7 +414,7 @@ void Design::drawOval(Graphics::Surface *surface, Common::ReadStream &in,
Graphics::drawEllipse(x1, y1, x2-1, y2-1, kColorBlack, false, drawPixel, &pd);
}
-void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &in) {
+void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in) {
int numBytes = in.readSint16BE();
int y1 = in.readSint16BE();
int x1 = in.readSint16BE();
@@ -410,7 +458,9 @@ void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &
color = b;
for (int c = 0; c < 8; c++) {
- if (x1 + x >= 0 && x1 + x < surface->w && y1 + y >= 0 && y1 + y < surface->h)
+ if (_boundsCalculationMode) {
+ adjustBounds(x1 + x, y1 + y);
+ } else if (x1 + x >= 0 && x1 + x < surface->w && y1 + y >= 0 && y1 + y < surface->h)
*((byte *)tmp.getBasePtr(x, y)) = (color & (1 << (7 - c % 8))) ? kColorBlack : kColorWhite;
x++;
if (x == w) {
@@ -424,37 +474,39 @@ void Design::drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &
in.skip(numBytes);
- FloodFill ff(&tmp, kColorWhite, kColorGreen);
- for (int yy = 0; yy < h; yy++) {
- ff.addSeed(0, yy);
- ff.addSeed(w - 1, yy);
- }
- for (int xx = 0; xx < w; xx++) {
- ff.addSeed(xx, 0);
- ff.addSeed(xx, h - 1);
- }
- ff.fill();
-
- for (y = 0; y < h; y++) {
- byte *src = (byte *)tmp.getBasePtr(0, y);
- byte *dst = (byte *)surface->getBasePtr(x1, y1 + y);
- for (x = 0; x < w; x++) {
- if (*src != kColorGreen)
- *dst = *src;
- src++;
- dst++;
+ if (!_boundsCalculationMode) {
+ Graphics::FloodFill ff(&tmp, kColorWhite, kColorGreen);
+ for (int yy = 0; yy < h; yy++) {
+ ff.addSeed(0, yy);
+ ff.addSeed(w - 1, yy);
+ }
+ for (int xx = 0; xx < w; xx++) {
+ ff.addSeed(xx, 0);
+ ff.addSeed(xx, h - 1);
+ }
+ ff.fill();
+
+ for (y = 0; y < h && y1 + y < surface->h; y++) {
+ byte *src = (byte *)tmp.getBasePtr(0, y);
+ byte *dst = (byte *)surface->getBasePtr(x1, y1 + y);
+ for (x = 0; x < w; x++) {
+ if (*src != kColorGreen)
+ *dst = *src;
+ src++;
+ dst++;
+ }
}
}
tmp.free();
}
-void Design::drawRect(Graphics::Surface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType) {
+void Design::drawRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType) {
drawRect(surface, rect.left, rect.top, rect.right, rect.bottom, thickness, color, patterns, fillType);
}
-void Design::drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
- PlotData pd(surface, &patterns, fillType, thickness);
+void Design::drawRect(Graphics::ManagedSurface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
+ PlotData pd(surface, &patterns, fillType, thickness, nullptr);
Graphics::drawLine(x1, y1, x2, y1, kColorBlack, drawPixel, &pd);
Graphics::drawLine(x2, y1, x2, y2, kColorBlack, drawPixel, &pd);
@@ -463,79 +515,29 @@ void Design::drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2
}
-void Design::drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType) {
- PlotData pd(surface, &patterns, fillType, 1);
+void Design::drawFilledRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType) {
+ PlotData pd(surface, &patterns, fillType, 1, nullptr);
for (int y = rect.top; y <= rect.bottom; y++)
Graphics::drawHLine(rect.left, rect.right, y, color, drawPixel, &pd);
}
-void Design::drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType) {
- PlotData pd(surface, &patterns, fillType, 1);
+void Design::drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType) {
+ PlotData pd(surface, &patterns, fillType, 1, nullptr);
Graphics::drawRoundRect(rect, arc, color, true, drawPixel, &pd);
}
-void Design::drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType) {
- PlotData pd(surface, &patterns, fillType, thickness);
+void Design::drawHLine(Graphics::ManagedSurface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType) {
+ PlotData pd(surface, &patterns, fillType, thickness, nullptr);
Graphics::drawHLine(x1, x2, y, color, drawPixel, &pd);
}
-void Design::drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
- PlotData pd(surface, &patterns, fillType, thickness);
+void Design::drawVLine(Graphics::ManagedSurface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType) {
+ PlotData pd(surface, &patterns, fillType, thickness, nullptr);
Graphics::drawVLine(x, y1, y2, color, drawPixel, &pd);
}
-FloodFill::FloodFill(Graphics::Surface *surface, byte color1, byte color2) {
- _surface = surface;
- _color1 = color1;
- _color2 = color2;
- _w = surface->w;
- _h = surface->h;
-
- _visited = (byte *)calloc(_w * _h, 1);
-}
-
-FloodFill::~FloodFill() {
- while(!_queue.empty()) {
- Common::Point *p = _queue.front();
-
- delete p;
- _queue.pop_front();
- }
-
- free(_visited);
-}
-
-void FloodFill::addSeed(int x, int y) {
- byte *p;
-
- if (x >= 0 && x < _w && y >= 0 && y < _h) {
- if (!_visited[y * _w + x] && *(p = (byte *)_surface->getBasePtr(x, y)) == _color1) {
- _visited[y * _w + x] = 1;
- *p = _color2;
-
- Common::Point *pt = new Common::Point(x, y);
-
- _queue.push_back(pt);
- }
- }
-}
-
-void FloodFill::fill() {
- while (!_queue.empty()) {
- Common::Point *p = _queue.front();
- _queue.pop_front();
- addSeed(p->x , p->y - 1);
- addSeed(p->x - 1, p->y );
- addSeed(p->x , p->y + 1);
- addSeed(p->x + 1, p->y );
-
- delete p;
- }
-}
-
-
} // End of namespace Wage
diff --git a/engines/wage/design.h b/engines/wage/design.h
index baa99730fe..86225c9224 100644
--- a/engines/wage/design.h
+++ b/engines/wage/design.h
@@ -48,10 +48,11 @@
#ifndef WAGE_DESIGN_H
#define WAGE_DESIGN_H
-#include "graphics/surface.h"
#include "common/memstream.h"
#include "common/rect.h"
+#include "wage/macwindowmanager.h"
+
namespace Wage {
class Design {
@@ -67,47 +68,36 @@ public:
return _bounds;
}
- void paint(Graphics::Surface *canvas, Patterns &patterns, int x, int y);
+ void paint(Graphics::ManagedSurface *canvas, Patterns &patterns, int x, int y);
bool isPointOpaque(int x, int y);
- static void drawRect(Graphics::Surface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType);
- static void drawRect(Graphics::Surface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType);
- static void drawFilledRect(Graphics::Surface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType);
- static void drawFilledRoundRect(Graphics::Surface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType);
- static void drawHLine(Graphics::Surface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType);
- static void drawVLine(Graphics::Surface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawRect(Graphics::ManagedSurface *surface, int x1, int y1, int x2, int y2, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawFilledRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int color, Patterns &patterns, byte fillType);
+ static void drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color, Patterns &patterns, byte fillType);
+ static void drawHLine(Graphics::ManagedSurface *surface, int x1, int x2, int y, int thickness, int color, Patterns &patterns, byte fillType);
+ static void drawVLine(Graphics::ManagedSurface *surface, int x, int y1, int y2, int thickness, int color, Patterns &patterns, byte fillType);
+ bool isBoundsCalculation() { return _boundsCalculationMode; }
+ void adjustBounds(int16 x, int16 y);
private:
byte *_data;
int _len;
Common::Rect *_bounds;
- Graphics::Surface *_surface;
+ Graphics::ManagedSurface *_surface;
+ bool _boundsCalculationMode;
private:
- void drawRect(Graphics::Surface *surface, Common::ReadStream &in,
+ void render(Patterns &patterns);
+ void drawRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawRoundRect(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawRoundRect(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawPolygon(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawPolygon(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawOval(Graphics::Surface *surface, Common::ReadStream &in,
+ void drawOval(Graphics::ManagedSurface *surface, Common::ReadStream &in,
Patterns &patterns, byte fillType, byte borderThickness, byte borderFillType);
- void drawBitmap(Graphics::Surface *surface, Common::SeekableReadStream &in);
-};
-
-class FloodFill {
-public:
- FloodFill(Graphics::Surface *surface, byte color1, byte color2);
- ~FloodFill();
- void addSeed(int x, int y);
- void fill();
-
-private:
- Common::List<Common::Point *> _queue;
- Graphics::Surface *_surface;
- byte _color1, _color2;
- byte *_visited;
- int _w, _h;
+ void drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in);
};
} // End of namespace Wage
diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp
index 91e20f3750..8b8a6399a8 100644
--- a/engines/wage/detection.cpp
+++ b/engines/wage/detection.cpp
@@ -41,7 +41,10 @@ static const PlainGameDescriptor wageGames[] = {
{"afm", "Another Fine Mess"},
{"amot", "A Mess O' Trouble"},
{"cantitoe", "Camp Cantitoe"},
+ {"drakmythcastle", "Drakmyth Castle"},
+ {"raysmaze", "Ray's Maze"},
{"scepters", "Enchanted Scepters"},
+ {"twisted", "Twisted!"},
{"wage", "WAGE"},
{0, 0}
};
@@ -51,8 +54,9 @@ static const PlainGameDescriptor wageGames[] = {
class WageMetaEngine : public AdvancedMetaEngine {
public:
WageMetaEngine() : AdvancedMetaEngine(Wage::gameDescriptions, sizeof(ADGameDescription), wageGames) {
- _singleid = "wage";
- _guioptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI);
+ _md5Bytes = 50000;
+ _singleId = "wage";
+ _guiOptions = GUIO2(GUIO_NOSPEECH, GUIO_NOMIDI);
}
virtual const char *getName() const {
@@ -97,7 +101,7 @@ SaveStateList WageMetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
char saveDesc[31];
Common::String pattern = target;
- pattern += ".???";
+ pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
diff --git a/engines/wage/detection_tables.h b/engines/wage/detection_tables.h
index 8723310294..59d93cc12f 100644
--- a/engines/wage/detection_tables.h
+++ b/engines/wage/detection_tables.h
@@ -22,33 +22,157 @@
namespace Wage {
-#define ADGF_DEFAULT (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM)
-#define ADGF_GENERIC (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_USEEXTRAASTITLE)
+#define ADGF_DEFAULT (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_MACRESFORK)
+#define ADGF_GENERIC (ADGF_DEFAULT|ADGF_USEEXTRAASTITLE|ADGF_AUTOGENTARGET)
+#define ADGF_DEMO (ADGF_GENERIC|ADGF_DEMO)
-#define FANGAME(n,f,m,s) { "wage",n,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()}
+#define FANGAME(n,m,s) { "wage",n,AD_ENTRY1s(n,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()}
+#define FANGAMEN(n,f,m,s) { "wage",n,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_GENERIC,GUIO0()}
+#define FANGAMEND(n,f,m,s) { "wage",n,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_DEMO,GUIO0()}
#define BIGGAME(t,v,f,m,s) { t,v,AD_ENTRY1s(f,m,s),Common::EN_ANY,Common::kPlatformMacintosh,ADGF_DEFAULT,GUIO0()}
static const ADGameDescription gameDescriptions[] = {
- FANGAME("3rd Floor", "3rd Floor", "a107d7a177970b2259e32681bd8b47c9", 285056),
- BIGGAME("afm", "v1.8", "Another Fine Mess 1.8", "8e5aa915f3253efb2aab52435647b25e", 1456000),
- BIGGAME("amot", "v1.8", "A Mess O' Trouble 1.8", "b3ef53afed282671b704e45df829350c", 1895552),
- FANGAME("Bug Hunt", "Bug Hunt", "2ebd3515a87941063ad66c3cf93c5e78", 200064),
- // Problems with letter rendering
- FANGAME("Canal District", "Canal District", "8856bc699a20fc5b7fc67accee12cac7", 658176),
- BIGGAME("cantitoe", "", "Camp Cantitoe", "098aa5c11c58e1ef274a30a9e01b4755", 621440),
- FANGAME("Deep Angst", "Deep Angst", "635f62bbc569e72b03cab9107927d03d", 335232),
- FANGAME("Dungeon World II", "DungeonWorld2", "e10c5e3cc17879c298b1551f33571b15", 234880),
+ FANGAME("3rd Floor", "3ed49d2163e46d2c9b33fd80927d9e22", 281409),
+ FANGAME("3rd Floor", "3ed49d2163e46d2c9b33fd80927d9e22", 281423), // alt version
+ BIGGAME("afm", "v1.8", "Another Fine Mess 1.8", "abc7188469a9a7083fd4caec55a4f76e", 1420723),
+ BIGGAME("amot", "v1.8", "A Mess O' Trouble 1.8", "6b59e5bb9a4b74ecdd9f66d4e36a59cf", 1843104),
+ // Crash on third screen
+ FANGAME("Brownie's Dream", "6fdcce532bcd50b7e4f3f6bab50a0ee6", 440704),
+ FANGAMEN("Brownie's Time Travels", "Brownie's Time Travels v1.2", "55842a100b56e236c5ad69563e01fc24", 471589),
+ FANGAME("Bug Hunt", "738e2e8a1020be48c5ef42da571674ae", 195699),
+ FANGAME("Bug Hunt", "118a41121143488719d28daa9af8cd39", 195779), // alt version
+ BIGGAME("cantitoe", "", "Camp Cantitoe", "1780c41d14b876461a19dbeceebf2a37", 616985),
+ FANGAME("Canal District", "34e7a8e84b33ba8ea38b4ffd76ef074f", 641470),
+ FANGAME("Carbon Copy", "9e781acd63290ae390d515cffc742011", 519445),
+ // Invalid rect in scene "FINALE"
+ FANGAME("Castle of Ert", "a45b439bb3a9c8a4a14b996024222068", 198955),
+ FANGAMEN("Castle of Ert", "Castle of Ert.1", "a45b439bb3a9c8a4a14b996024222068", 198983), // alt version
+ FANGAMEND("Death Mall", "Death Mall Demo", "1c78fc15fb037b242a0bc6bac7d4d889", 254874),
+ FANGAME("Deep Angst", "7f8821f7b279269a91f9aadfed98eec0", 329550), // Original gile name "Deep Angstâ„¢"
+ FANGAME("Deep Ennui", "7fa4368834a22a9d4b7246a6297b455f", 86075),
// Polygons with ignored byte 1
- FANGAME("Double Trouble", "Double Trouble", "5e9ee13d09ac54918ed111fa9727ac1c", 557184),
- FANGAME("Eidisi I", "Eidisi I", "299d1de4baccf1c66118396519953652", 180480),
- FANGAME("Escape from School!", "Escape from School!", "a854be48d4af20126d18a9cad93a969b", 51840),
- FANGAME("Magic Rings", "Magic Rings", "6e0d1dd561d3dad8f9a7a20ed1f09b16", 112000),
- FANGAME("Midnight Snack", "Midnight Snack", "346982a32fc701f53bb19771d72063d0", 69504),
- FANGAME("Queen Quest", "Queen Quest", "730605d312efedb5e3ff108522fcac18", 59776),
- BIGGAME("scepters", "", "Scepters", "b80bff315897776dda7689cdf829fab4", 360832),
- FANGAME("Time Bomb", "Time Bomb", "2df84b636237686b624e736a698a16c4", 66432),
- FANGAME("ZikTuria", "ZikTuria", "e793155bed1a70fa2074a3fcd696b751", 54784),
- FANGAME("Zoony", "Zoony", "e6cc8a914a4215dafbcce6315dd12cf5", 160256),
+ FANGAME("Double Trouble", "3f0c032377d87704267283380800633a", 542371),
+ BIGGAME("drakmythcastle", "disk I", "Drakmyth Castle disk I of II", "5b1fd760fbc081c608acebfe1d07a58a", 793784),
+ BIGGAME("drakmythcastle", "disk II", "Drakmyth Castle II", "1116f9c2c781f79e1f9c868b51ae7fa5", 1685659),
+ // Crash at start in GUI rendering
+ FANGAME("Dune Eternity", "6b29f82e235815ffc4c9f30dc09968dd", 290201), // Original file name is "***DUNE ETERNITY*** "
+ FANGAMEN("Dungeon World II", "DungeonWorld2", "753df07166ca48e303d782cc72dd4053", 230199),
+ // Made for bigger resolution
+ FANGAME("Dynasty of Dar", "b2e9a5cca28acb85617b1477a5fca3e2", 275693),
+ FANGAME("Edg's World", "0a3a3aaa36088c514b668f1f62120006", 106769),
+ FANGAME("Eidisi I", "3d778c0fe7addf5f29e7593ba0fd3953", 172552),
+ FANGAME("Eidisi I", "8c2fb325a49344568c5536bba36a2556", 172566), // alt version
+ // Problems(?) with text on the first screen
+ FANGAMEN("Enchanted Pencils", "Enchanted Pencils 0.99 (PG)", "9a9777a83e58bebfa6f1662d5e236384", 408913),
+ FANGAME("Escape!", "3ada261c2d1d9ce6b9da068237472689", 65075), // Original file name "Escape!†"
+ FANGAME("Escape from School!", "2055747bb874052333190eb993246a7f", 50105),
+ FANGAME("Escape from School!", "fcc581e52d1fc8ea4603d7c953fa935a", 50119), // Original file name "Escape from School!†"
+ FANGAME("Everyman 1", "e20cebf0091a1b1bf023aac6f28c9011", 335705),
+ FANGAME("Exploration Zeta!", "6127d9c04ad68f0cbb5f6aa1d95b48a2", 366599),
+ // Cannot proceed past the first scene
+ FANGAMEND("Explorer", "Explorer DEMO", "a9ebdecf6c8de95a03e593d877dacc13", 461228),
+ // Crash in console rendering on the first scene
+ FANGAME("Fantasy Quest", "b42b0e86e2c84464283640c74b25e015", 762754),
+ FANGAME("Find the Heart", "aa244c15f2ba8cef468714be34223acd", 106235), // From Joshua's Worlds 1.0
+ FANGAME("Find the Heart", "a6834cb230cea1953f5bf1f8f7aacabd", 105885), // From Joshua's Worlds. Alt version
+ FANGAME("Find the Heart", "a6834cb230cea1953f5bf1f8f7aacabd", 105871), // Standalone
+ FANGAMEN("Fortune Teller", "Fortune Teller 1.1", "7d2628eeea67b33379e01c0aef8dd196", 73931),
+ FANGAMEN("Haunted House", "Haunted House 1.5", "5db2f95c7abaa9d060b94271a5bc57f8", 177500),
+ // Cropped graphics on first scene
+ FANGAME("Intro to Gothic", "6f732eaad6e3b85795f8ee6c6a40d837", 208067),
+ // No Next button in intro
+ FANGAME("Jamie the Demon Slayer", "fa0ca9618c18425b6d9bf913f762d91b", 232789),
+ FANGAMEN("Journey", "The Journey 1.6.2 US", "e66f37472e1414a088eb5d5acc4df794", 820572),
+ FANGAMEN("Jumble", "LSJUMBLE", "7c46851d2f90c7da9efe40b1688869c2", 647339), // Original file name is "LSJUMBLE† "
+ FANGAME("Karth of the Jungle", "5f2346834821dc3c4008e139cd37b3cb", 96711),
+ FANGAME("Karth of the Jungle", "444f9426f342135fbcc32180e5ba5b1c", 96960), // Alternative version
+ FANGAME("Karth of the Jungle II", "32161b27de894fd9e3f054afc4013f34", 201053),
+ FANGAMEN("Little Pythagoras", "Little Pythagoras 1.1.1", "75906fa955de695ac3e8164e7d88ac7b", 628821),
+ FANGAME("Lost Crystal", "d5e27a83f2884a24c6ec26c6cb776fe9", 771072),
+ // Crash in design drawing on startup
+ FANGAMEN("Lost In Kookyville", "Lost In Kookyville 1.2.4", "5ab6259706b33230dbfba05618c2c5c9", 721569),
+ FANGAME("Magic Rings", "450e986694b96f3b9e6cc64e57b753dc", 109044),
+ // No way to click on the house
+ FANGAME("Messy House", "705df61da9e7d742b7ad678e59eb7bfb", 177120),
+ FANGAME("Midnight Snack", "76986389f9a08dd95450c8b9cf408653", 67952),
+ FANGAME("Midnight Snack", "76986389f9a08dd95450c8b9cf408653", 67966), // Alt version
+ FANGAME("Mike's House", "3d23c2b88cefd958bcbc4d4c711003d8", 87357),
+ FANGAME("Minitorian", "15fbb2bd75d83155ed21edbc5dc9558f", 586464),
+ FANGAME("M'Lord's Warrior", "0bebb2c62529c89590f6c5be6e1e9838", 465639), // Original file name is "M'Lord's Warrior †"
+ // Unhandled comparison case
+ FANGAME("Mountain of Mayhem", "4088fc534042081b7ab7b49675ab4a6e", 750003), // Original file name "Mountain of Mayhem †"
+ // No way to pass through the first screen
+ FANGAME("Nightcrawler Ned", "0cf27bf82de299c69405f7910146bf00", 366542),
+ // Crash on startup
+ FANGAMEN("Parrot Talk", "PARROT TALK V1", "b1570b0779891d5d50a3cf0146d28202", 118936),
+ // Crash on startup
+ FANGAMEN("Parrot Talk", "PARROT TALKV2", "0c1e920ed3ff74b8f22eaaf0d3496d5a", 118884),
+ FANGAME("Pavilion", "3a33149569325a44d98544452323c819", 231687),
+ FANGAMEN("Pencils", "Pencils.99", "9c200938488565080e12989e784586e2", 408551),
+ // Polygons with byte 1
+ FANGAME("Periapt", "fb4052819126b88d7e03ebc00c669a9d", 406006),
+ FANGAME("Psychotic!", "6b4ae6261b405e2feac58c5a2ddb67c5", 247693),
+ FANGAME("Puzzle Piece Search", "6b4ae6261b405e2feac58c5a2ddb67c5", 247693), // From Joshua's Worlds 1.0
+ FANGAME("The Puzzle Piece Search", "fb99797c429c18ec68418fdd12af17a1", 247338), // From Joshua's Worlds
+ FANGAME("The Puzzle Piece Search", "fb99797c429c18ec68418fdd12af17a1", 247324), // Stnadalone
+ // Empty(?) first scene
+ FANGAME("Pyramid of No Return", "38383ac85cc16703f13f8d82f1398123", 385145),
+ // Cropped graphics at the first scene
+ FANGAME("Psychotic!", "29b30e6aae9cc6db5eccb09f695ff25e", 367309),
+ FANGAME("P-W Adventure", "9bf86fb946683500d23887ef185726ab", 219216),
+ FANGAMEN("Pyramid of Ert", "Pyramid of Ert V1.2", "fb931cd35440a66864a434c773b496da", 315783),
+ FANGAME("Queen Quest", "8273e29afe64a984eb0ce7b43fdf3a59", 57039), // alt version
+ FANGAME("Quest for T-Rex", "f16f2cd525c9aeb4733295d8d842b902", 592584),
+ // Crash in console rendering on the initial scene
+ FANGAME("Quest for the Dark Sword", "4815d9a770904b26c463b7e4fcd121c7", 572576),
+ FANGAME("Radical Castle", "09b70763c7a48a76240bd0e42737caaa", 355601),
+ FANGAME("Radical Castle 1.0", "8ae2e29ffeca52a5c7fae66dec4764a3", 347278),
+ BIGGAME("raysmaze", "v1.5", "Ray's Maze1.5", "521583e59bdc1d611f963cef1dc25869", 1408516),
+ BIGGAME("raysmaze", "v1.5/alt", "Ray's Maze1.5", "120e65bec953b981b2e0aed45ad45d70", 1408516),
+ // Next button is not visible
+ FANGAME("Ray's World Builder Demo", "d252ee8e38c9abc50455d071a367d031", 116056),
+ // Unhandled comparison case
+ FANGAME("Sands of Time", "b00ea866cb04cd87124e5720bc2c84c7", 122672), // Original file name "Sands of Time†"
+ BIGGAME("scepters", "", "Scepters", "f8db17cd96be056cf8a8bb9cfe46cf3a", 346595),
+ BIGGAME("scepters", "", "Scepters", "1fd7ca93ef16f4752fb46ee9cfa0949a", 347540), // alt version
+ FANGAME("Schmoozer", "e0f416bae626e2c638055b7f495d8c78", 221500),
+ // ??? problems with dog bitmap?
+ FANGAMEN("Space Adventure", "SpaceAdventure", "7b6c883b3510e21cfabf4c8caaeb1f16", 155356),
+ FANGAMEN("Space Adventure", "SpaceAdventure", "3bd6fc9327f35db5390a9bf86afcd872", 155356), // alt version
+ FANGAMEN("Spear of Destiny", "SpearOfDestiny", "f1252ff34dd279f4ec1844bb403a578c", 333665), // Original file name "SpearOfDestiny†"
+ FANGAME("Star Trek", "fe20d06bc50c7fcebda0db533e141d4a", 53320),
+ FANGAME("Strange Disappearance", "782fae517f7374cd7f43f428331ce445", 772282),
+ // Code 0x03 in text
+ FANGAME("Swamp Witch", "4f146c0a5c59e7d4717a0423271fa89d", 739781), // Original file name "Swamp Witch†"
+ FANGAME("Sweetspace Now!", "1d419bc0b04c51468ddc40a90125bf00", 123813), // Comes with Jumble
+ // Wrong scrolling in the first console text
+ FANGAMEN("Sword of Siegfried", "Sword of Siegfried 1.0", "1ee92830690f89ea142ac0847176a0c3", 234763),
+ FANGAME("Terrorist", "68208fa5e426312fb12402894add5e4a", 524469), // Original file name "Terrorist†"
+ FANGAME("Time Bomb", "b7a369d57d43ec8d9fd53832fd38d7db", 64564),
+ FANGAME("Time Bomb", "b7a369d57d43ec8d9fd53832fd38d7db", 64578), // Alt version
+ FANGAMEND("The Ashland Revolution", "The Ashland Revolution Demo", "3c7a1bdeab48a077a4f54fe69da61a9f", 145023), // Original file name "The Ashland Revolution Demo†"
+ FANGAME("The Axe-orcist", "bfdf6a4ce87e6b368977af3b683466db", 308764),
+ FANGAMEN("The Hotel Caper", "The Hotel Caper V1.0", "0d11a6ca1357e27ffff5231fe89cc429", 231969),
+ FANGAMEN("The Hotel Caper", "The Hotel Caper V1.0", "6c80fa6a36d16aa0edef86d8800c90db", 231969), // alt version
+ // Invalid rect in scene "Access Tube 1"
+ FANGAMEN("The Phoenix v1.2", "The Phoenix", "0a4a01b83c993408ae824cc4f63957ea", 431640),
+ FANGAME("The Phoenix", "0a4a01b83c993408ae824cc4f63957ea", 431643),
+ FANGAME("The Sultan's Palace", "98c845323489344d7e2c9d1c3e53d1fc", 456855),
+ // Admission for on 3rd screen is messed up
+ FANGAME("The Tower", "135fe861928d15b5acd8b355460c54bf", 556539),
+ // Polygons with ignored byte 1 and 2 on second scene
+ FANGAME("The Village", "b9b5cfbfc7f482eae7587b55edc135ed", 314828),
+ FANGAME("The Wizard's Apprentice", "7eff3cb7d1a3f59639c62cf196039745", 782824),
+ // Messed up first scene
+ FANGAMEND("Tombworld", "Demo TombWorld", "f7c86166e29fb8b57f7a1400d4963a4e", 664252), // Original file name "Demo TombWorld©"
+ // Doesn't go past first scene
+ BIGGAME("twisted", "", "Twisted! 1.6", "97ab265eddf0cfed6d43d062c853cbc0", 960954),
+ FANGAME("Volcano II", "4dbb7ec6111c0f872da8ed8ba14763c9", 82991), // Original file name "Volcano II†"
+ FANGAME("Wishing Well", "ece06c419cbb2d32941e6b5c7d9d7c1a", 103688),
+ FANGAME("Wizard's Warehouse", "ee1b86841583e2b58ac39bf97017dc7b", 159748),
+ FANGAMEN("Wizard's Warehouse 2", "WizWarehouse 2.0", "6502bd974fe149fe76d6d5ae9d1e6878", 230870),
+ FANGAME("ZikTuria", "1b934fca68d633d231dccd2047d2d274", 52972),
+ FANGAME("Zoony", "7bb293b81117cbd974ce54fafa06f258", 154990), // original filename "Zoonyâ„¢"
AD_TABLE_END_MARKER
};
diff --git a/engines/wage/dialog.cpp b/engines/wage/dialog.cpp
index 263570bddc..86080c9a6f 100644
--- a/engines/wage/dialog.cpp
+++ b/engines/wage/dialog.cpp
@@ -49,6 +49,7 @@
#include "common/events.h"
#include "wage/wage.h"
+#include "wage/macwindowmanager.h"
#include "wage/design.h"
#include "wage/gui.h"
#include "wage/dialog.h"
@@ -85,14 +86,16 @@ Dialog::Dialog(Gui *gui, int width, const char *text, DialogButtonArray *buttons
}
Dialog::~Dialog() {
+ for (uint i = 0; i < _buttons->size(); i++)
+ delete _buttons->operator[](i);
}
const Graphics::Font *Dialog::getDialogFont() {
- return _gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+ return _gui->_wm.getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
}
void Dialog::paint() {
- Design::drawFilledRect(&_gui->_screen, _bbox, kColorWhite, _gui->_patterns, kPatternSolid);
+ Design::drawFilledRect(&_gui->_screen, _bbox, kColorWhite, _gui->_wm.getPatterns(), kPatternSolid);
_font->drawString(&_gui->_screen, _text, _bbox.left + 24, _bbox.top + 16, _bbox.width(), kColorBlack);
static int boxOutline[] = { 1, 0, 0, 1, 1 };
@@ -114,7 +117,7 @@ void Dialog::paint() {
Common::Rect bb(button->bounds.left + 5, button->bounds.top + 5,
button->bounds.right - 5, button->bounds.bottom - 5);
- Design::drawFilledRect(&_gui->_screen, bb, kColorBlack, _gui->_patterns, kPatternSolid);
+ Design::drawFilledRect(&_gui->_screen, bb, kColorBlack, _gui->_wm.getPatterns(), kPatternSolid);
color = kColorWhite;
}
@@ -137,7 +140,7 @@ void Dialog::drawOutline(Common::Rect &bounds, int *spec, int speclen) {
for (int i = 0; i < speclen; i++)
if (spec[i] != 0)
Design::drawRect(&_gui->_screen, bounds.left + i, bounds.top + i, bounds.right - i, bounds.bottom - i,
- 1, kColorBlack, _gui->_patterns, kPatternSolid);
+ 1, kColorBlack, _gui->_wm.getPatterns(), kPatternSolid);
}
int Dialog::run() {
@@ -145,7 +148,7 @@ int Dialog::run() {
Common::Rect r(_bbox);
_tempSurface.copyRectToSurface(_gui->_screen.getBasePtr(_bbox.left, _bbox.top), _gui->_screen.pitch, 0, 0, _bbox.width() + 1, _bbox.height() + 1);
- _gui->pushArrowCursor();
+ _gui->_wm.pushArrowCursor();
while (!shouldQuit) {
Common::Event event;
@@ -189,7 +192,7 @@ int Dialog::run() {
_gui->_screen.copyRectToSurface(_tempSurface.getBasePtr(0, 0), _tempSurface.pitch, _bbox.left, _bbox.top, _bbox.width() + 1, _bbox.height() + 1);
g_system->copyRectToScreen(_gui->_screen.getBasePtr(r.left, r.top), _gui->_screen.pitch, r.left, r.top, r.width() + 1, r.height() + 1);
- _gui->popCursor();
+ _gui->_wm.popCursor();
return _pressedButton;
}
diff --git a/engines/wage/dialog.h b/engines/wage/dialog.h
index c5878acc95..ec99fc06b2 100644
--- a/engines/wage/dialog.h
+++ b/engines/wage/dialog.h
@@ -74,7 +74,7 @@ public:
private:
Gui *_gui;
- Graphics::Surface _tempSurface;
+ Graphics::ManagedSurface _tempSurface;
Common::Rect _bbox;
Common::String _text;
diff --git a/engines/wage/entities.cpp b/engines/wage/entities.cpp
index d9e4b60591..43ac6c8cc7 100644
--- a/engines/wage/entities.cpp
+++ b/engines/wage/entities.cpp
@@ -52,6 +52,7 @@
#include "wage/world.h"
#include "common/memstream.h"
+#include "graphics/managed_surface.h"
namespace Wage {
@@ -97,6 +98,8 @@ Scene::Scene() {
}
Scene::Scene(Common::String name, Common::SeekableReadStream *data) {
+ debug(9, "Creating scene: %s", name.c_str());
+
_name = name;
_classType = SCENE;
_design = new Design(data);
@@ -132,20 +135,20 @@ Scene::~Scene() {
delete _textBounds;
}
-void Scene::paint(Graphics::Surface *surface, int x, int y) {
+void Scene::paint(Graphics::ManagedSurface *surface, int x, int y) {
Common::Rect r(x + 5, y + 5, _design->getBounds()->width() + x - 10, _design->getBounds()->height() + y - 10);
surface->fillRect(r, kColorWhite);
- _design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y);
+ _design->paint(surface, *((WageEngine *)g_engine)->_world->_patterns, x, y);
for (ObjList::const_iterator it = _objs.begin(); it != _objs.end(); ++it) {
- debug(2, "paining Obj: %s", (*it)->_name.c_str());
- (*it)->_design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y);
+ debug(2, "paining Obj: %s, index: %d, type: %d", (*it)->_name.c_str(), (*it)->_index, (*it)->_type);
+ (*it)->_design->paint(surface, *((WageEngine *)g_engine)->_world->_patterns, x, y);
}
for (ChrList::const_iterator it = _chrs.begin(); it != _chrs.end(); ++it) {
debug(2, "paining Chr: %s", (*it)->_name.c_str());
- (*it)->_design->paint(surface, ((WageEngine *)g_engine)->_world->_patterns, x, y);
+ (*it)->_design->paint(surface, *((WageEngine *)g_engine)->_world->_patterns, x, y);
}
}
@@ -200,6 +203,22 @@ const char *Scene::getFontName() {
return "Unknown";
}
+Designed *Scene::lookUpEntity(int x, int y) {
+ for (ObjList::const_iterator it = _objs.end(); it != _objs.begin(); ) {
+ it--;
+ if ((*it)->_design->isPointOpaque(x, y))
+ return *it;
+ }
+
+ for (ChrList::const_iterator it = _chrs.end(); it != _chrs.begin(); ) {
+ it--;
+ if ((*it)->_design->isPointOpaque(x, y))
+ return *it;
+ }
+
+ return nullptr;
+}
+
Obj::Obj() : _currentOwner(NULL), _currentScene(NULL) {
_index = 0;
_namePlural = false;
diff --git a/engines/wage/entities.h b/engines/wage/entities.h
index 33cf087322..9e706f0d58 100644
--- a/engines/wage/entities.h
+++ b/engines/wage/entities.h
@@ -49,7 +49,7 @@
#define WAGE_ENTITIES_H
namespace Graphics {
- struct Surface;
+ class ManagedSurface;
}
namespace Wage {
@@ -322,11 +322,13 @@ public:
Scene(Common::String name, Common::SeekableReadStream *data);
~Scene();
+ Designed *lookUpEntity(int x, int y);
+
Common::Rect *getTextBounds() {
return _textBounds == NULL ? NULL : new Common::Rect(*_textBounds);
}
- void paint(Graphics::Surface *screen, int x, int y);
+ void paint(Graphics::ManagedSurface *screen, int x, int y);
const char *getFontName();
};
diff --git a/engines/wage/gui-console.cpp b/engines/wage/gui-console.cpp
index ab5df637ec..8b6fe43a17 100644
--- a/engines/wage/gui-console.cpp
+++ b/engines/wage/gui-console.cpp
@@ -45,6 +45,7 @@
*
*/
+#include "common/events.h"
#include "common/timer.h"
#include "common/unzip.h"
#include "graphics/cursorman.h"
@@ -54,7 +55,8 @@
#include "wage/wage.h"
#include "wage/design.h"
#include "wage/entities.h"
-#include "wage/menu.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
#include "wage/gui.h"
#include "wage/world.h"
@@ -66,7 +68,7 @@ const Graphics::Font *Gui::getConsoleFont() {
snprintf(fontName, 128, "%s-%d", scene->getFontName(), scene->_fontSize);
- return getFont(fontName, Graphics::FontManager::kConsoleFont);
+ return _wm.getFont(fontName, Graphics::FontManager::kConsoleFont);
}
void Gui::clearOutput() {
@@ -114,7 +116,7 @@ enum {
void Gui::flowText(Common::String &str) {
Common::StringArray wrappedLines;
- int textW = _consoleTextArea.width() - kConWPadding * 2;
+ int textW = _consoleWindow->getInnerDimensions().width() - kConWPadding * 2;
const Graphics::Font *font = getConsoleFont();
font->wordWrapText(str, textW, wrappedLines);
@@ -142,7 +144,7 @@ void Gui::flowText(Common::String &str) {
draw();
}
-void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
+void Gui::renderConsole(Graphics::ManagedSurface *g, const Common::Rect &r) {
bool fullRedraw = _consoleFullRedraw;
bool textReflow = false;
int surfW = r.width() + kConWOverlap * 2;
@@ -150,7 +152,6 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
Common::Rect boundsR(kConWOverlap - kConOverscan, kConHOverlap - kConOverscan,
r.width() + kConWOverlap + kConOverscan, r.height() + kConHOverlap + kConOverscan);
- Common::Rect fullR(0, 0, surfW, surfH);
if (_console.w != surfW || _console.h != surfH) {
if (_console.w != surfW)
@@ -163,7 +164,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
}
if (fullRedraw)
- _console.fillRect(fullR, kColorWhite);
+ _console.clear(kColorWhite);
const Graphics::Font *font = getConsoleFont();
@@ -197,7 +198,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
color = kColorWhite;
Common::Rect trect(0, y1, _console.w, y1 + _consoleLineHeight);
- Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid);
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
}
if (line == _selectionStartY || line == _selectionEndY) {
@@ -224,7 +225,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
else
trect.left = rectW;
- Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid);
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
font->drawString(&_console, beg, x1, y1, textW, color1);
font->drawString(&_console, end, x1 + rectW - kConWPadding - kConWOverlap, y1, textW, color2);
@@ -243,7 +244,7 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
int rectW2 = rectW1 + font->getStringWidth(mid);
Common::Rect trect(rectW1, y1, rectW2, y1 + _consoleLineHeight);
- Design::drawFilledRect(&_console, trect, kColorBlack, _patterns, kPatternSolid);
+ Design::drawFilledRect(&_console, trect, kColorBlack, _wm.getPatterns(), kPatternSolid);
font->drawString(&_console, beg, x1, y1, textW, kColorBlack);
font->drawString(&_console, mid, x1 + rectW1 - kConWPadding - kConWOverlap, y1, textW, kColorWhite);
@@ -280,17 +281,13 @@ void Gui::renderConsole(Graphics::Surface *g, Common::Rect &r) {
rr.bottom = _screen.h - 1;
g->copyRectToSurface(_console, xcon, ycon, boundsR);
- g_system->copyRectToScreen(g->getBasePtr(rr.left, rr.top), g->pitch, rr.left, rr.top, rr.width(), rr.height());
}
void Gui::drawInput() {
if (!_screen.getPixels())
return;
- if (_sceneIsActive) {
- _sceneIsActive = false;
- _bordersDirty = true;
- }
+ _wm.setActive(_consoleWindow->getId());
_out.pop_back();
_lines.pop_back();
@@ -302,17 +299,17 @@ void Gui::drawInput() {
if (_engine->_inputText.contains('\n')) {
_consoleDirty = true;
} else {
- int x = kConWPadding + _consoleTextArea.left;
- int y = _cursorY + _consoleTextArea.top;
+ int x = kConWPadding + _consoleWindow->getInnerDimensions().left;
+ int y = _cursorY + _consoleWindow->getInnerDimensions().top;
- Common::Rect r(x, y, x + _consoleTextArea.width() - kConWPadding, y + font->getFontHeight());
+ Common::Rect r(x, y, x + _consoleWindow->getInnerDimensions().width() - kConWPadding, y + font->getFontHeight());
_screen.fillRect(r, kColorWhite);
undrawCursor();
font->drawString(&_screen, _out[_inputTextLineNum], x, y, _screen.w, kColorBlack);
- g_system->copyRectToScreen(_screen.getBasePtr(x, y), _screen.pitch, x, y, _consoleTextArea.width(), font->getFontHeight());
+ g_system->copyRectToScreen(_screen.getBasePtr(x, y), _screen.pitch, x, y, _consoleWindow->getInnerDimensions().width(), font->getFontHeight());
}
_cursorX = font->getStringWidth(_out[_inputTextLineNum]) + kConHPadding;
@@ -427,4 +424,140 @@ void Gui::enableNewGameMenus() {
_menu->enableCommand(kMenuFile, kMenuActionQuit, true);
}
+bool Gui::processConsoleEvents(WindowClick click, Common::Event &event) {
+ if (click == kBorderScrollUp || click == kBorderScrollDown) {
+ if (event.type == Common::EVENT_LBUTTONDOWN) {
+ int consoleHeight = _consoleWindow->getInnerDimensions().height();
+ int textFullSize = _lines.size() * _consoleLineHeight + consoleHeight;
+ float scrollPos = (float)_scrollPos / textFullSize;
+ float scrollSize = (float)consoleHeight / textFullSize;
+
+ _consoleWindow->setScroll(scrollPos, scrollSize);
+
+ return true;
+ } else if (event.type == Common::EVENT_LBUTTONUP) {
+ int oldScrollPos = _scrollPos;
+
+ switch (click) {
+ case kBorderScrollUp:
+ _scrollPos = MAX<int>(0, _scrollPos - _consoleLineHeight);
+ undrawCursor();
+ _cursorY -= (_scrollPos - oldScrollPos);
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+ break;
+ case kBorderScrollDown:
+ _scrollPos = MIN<int>((_lines.size() - 2) * _consoleLineHeight, _scrollPos + _consoleLineHeight);
+ undrawCursor();
+ _cursorY -= (_scrollPos - oldScrollPos);
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ if (click == kBorderResizeButton) {
+ _consoleDirty = true;
+ _consoleFullRedraw = true;
+
+ return true;
+ }
+
+ if (click == kBorderInner) {
+ if (event.type == Common::EVENT_LBUTTONDOWN) {
+ startMarking(event.mouse.x, event.mouse.y);
+
+ return true;
+ } else if (event.type == Common::EVENT_LBUTTONUP) {
+ if (_inTextSelection) {
+ _inTextSelection = false;
+
+ if (_selectionEndY == -1 ||
+ (_selectionEndX == _selectionStartX && _selectionEndY == _selectionStartY)) {
+ _selectionStartY = _selectionEndY = -1;
+ _consoleFullRedraw = true;
+ _menu->enableCommand(kMenuEdit, kMenuActionCopy, false);
+ } else {
+ _menu->enableCommand(kMenuEdit, kMenuActionCopy, true);
+
+ bool cutAllowed = false;
+
+ if (_selectionStartY == _selectionEndY && _selectionStartY == (int)_lines.size() - 1)
+ cutAllowed = true;
+
+ _menu->enableCommand(kMenuEdit, kMenuActionCut, cutAllowed);
+ _menu->enableCommand(kMenuEdit, kMenuActionClear, cutAllowed);
+ }
+ }
+
+ return true;
+ } else if (event.type == Common::EVENT_MOUSEMOVE) {
+ if (_inTextSelection) {
+ updateTextSelection(event.mouse.x, event.mouse.y);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+int Gui::calcTextX(int x, int textLine) {
+ const Graphics::Font *font = getConsoleFont();
+
+ if ((uint)textLine >= _lines.size())
+ return 0;
+
+ Common::String str = _lines[textLine];
+
+ x -= _consoleWindow->getInnerDimensions().left;
+
+ for (int i = str.size(); i >= 0; i--) {
+ if (font->getStringWidth(str) < x) {
+ return i;
+ }
+
+ str.deleteLastChar();
+ }
+
+ return 0;
+}
+
+int Gui::calcTextY(int y) {
+ y -= _consoleWindow->getInnerDimensions().top;
+
+ if (y < 0)
+ y = 0;
+
+ const int firstLine = _scrollPos / _consoleLineHeight;
+ int textLine = (y - _scrollPos % _consoleLineHeight) / _consoleLineHeight + firstLine;
+
+ return textLine;
+}
+
+void Gui::startMarking(int x, int y) {
+ _selectionStartY = calcTextY(y);
+ _selectionStartX = calcTextX(x, _selectionStartY);
+
+ _selectionEndY = -1;
+
+ _inTextSelection = true;
+}
+
+void Gui::updateTextSelection(int x, int y) {
+ _selectionEndY = calcTextY(y);
+ _selectionEndX = calcTextX(x, _selectionEndY);
+
+ _consoleFullRedraw = true;
+}
+
} // End of namespace Wage
diff --git a/engines/wage/gui.cpp b/engines/wage/gui.cpp
index 387731cc18..099279158f 100644
--- a/engines/wage/gui.cpp
+++ b/engines/wage/gui.cpp
@@ -46,73 +46,44 @@
*/
#include "common/timer.h"
-#include "common/unzip.h"
+#include "common/system.h"
#include "graphics/cursorman.h"
-#include "graphics/fonts/bdf.h"
-#include "graphics/palette.h"
+#include "graphics/primitives.h"
#include "wage/wage.h"
#include "wage/design.h"
#include "wage/entities.h"
-#include "wage/menu.h"
#include "wage/gui.h"
+#include "wage/macwindow.h"
+#include "wage/macwindowmanager.h"
+#include "wage/macmenu.h"
#include "wage/world.h"
namespace Wage {
-static const byte palette[] = {
- 0, 0, 0, // Black
- 0x80, 0x80, 0x80, // Gray
- 0xff, 0xff, 0xff, // White
- 0x00, 0xff, 0x00 // Green
-};
-
-static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid
- { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes
- { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers
- { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } // kPatternCheckers2
-};
-
-static const byte macCursorArrow[] = {
- 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 2, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 2, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3,
- 2, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3,
- 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3,
- 2, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3,
- 2, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3,
- 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3,
- 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
- 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
- 2, 0, 0, 2, 0, 0, 2, 3, 3, 3, 3,
- 2, 0, 2, 3, 2, 0, 0, 2, 3, 3, 3,
- 2, 2, 3, 3, 2, 0, 0, 2, 3, 3, 3,
- 2, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
- 3, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
- 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3
-};
-
-static const byte macCursorBeam[] = {
- 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
- 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
- 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+static const MenuData menuSubItems[] = {
+ { kMenuHighLevel, "File", 0, 0, false },
+ { kMenuHighLevel, "Edit", 0, 0, false },
+ { kMenuFile, "New", kMenuActionNew, 0, false },
+ { kMenuFile, "Open...", kMenuActionOpen, 0, false },
+ { kMenuFile, "Close", kMenuActionClose, 0, true },
+ { kMenuFile, "Save", kMenuActionSave, 0, false },
+ { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true },
+ { kMenuFile, "Revert", kMenuActionRevert, 0, false },
+ { kMenuFile, "Quit", kMenuActionQuit, 0, true },
+
+ { kMenuEdit, "Undo", kMenuActionUndo, 'Z', false },
+ { kMenuEdit, NULL, 0, 0, false },
+ { kMenuEdit, "Cut", kMenuActionCut, 'K', false },
+ { kMenuEdit, "Copy", kMenuActionCopy, 'C', false },
+ { kMenuEdit, "Paste", kMenuActionPaste, 'V', false },
+ { kMenuEdit, "Clear", kMenuActionClear, 'B', false },
+
+ { 0, NULL, 0, 0, false }
};
static void cursorTimerHandler(void *refCon) {
- Gui *gui = (Gui *)refCon;
+ Gui *gui = (Gui *)refCon;
int x = gui->_cursorX;
int y = gui->_cursorY;
@@ -123,8 +94,8 @@ static void cursorTimerHandler(void *refCon) {
if (!gui->_screen.getPixels())
return;
- x += gui->_consoleTextArea.left;
- y += gui->_consoleTextArea.top;
+ x += gui->_consoleWindow->getInnerDimensions().left;
+ y += gui->_consoleWindow->getInnerDimensions().top;
gui->_screen.vLine(x, y, y + kCursorHeight, gui->_cursorState ? kColorBlack : kColorWhite);
@@ -139,22 +110,25 @@ static void cursorTimerHandler(void *refCon) {
gui->_cursorDirty = true;
}
+static bool sceneWindowCallback(WindowClick click, Common::Event &event, void *gui);
+static bool consoleWindowCallback(WindowClick click, Common::Event &event, void *gui);
+static void menuCommandsCallback(int action, Common::String &text, void *data);
+
+
Gui::Gui(WageEngine *engine) {
_engine = engine;
_scene = NULL;
_sceneDirty = true;
_consoleDirty = true;
- _bordersDirty = true;
- _menuDirty = true;
_cursorDirty = false;
_consoleFullRedraw = true;
_screen.create(g_system->getWidth(), g_system->getHeight(), Graphics::PixelFormat::createFormatCLUT8());
+ _wm.setScreen(&_screen);
+
_scrollPos = 0;
_consoleLineHeight = 8; // Dummy value which makes sense
_consoleNumLines = 24; // Dummy value
- _builtInFonts = false;
- _sceneIsActive = false;
_cursorX = 0;
_cursorY = 0;
@@ -167,28 +141,39 @@ Gui::Gui(WageEngine *engine) {
_inputTextLineNum = 0;
- g_system->getPaletteManager()->setPalette(palette, 0, 4);
+ g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "wageCursor");
+
+ _menu = _wm.addMenu();
- CursorMan.replaceCursorPalette(palette, 0, 4);
- CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
- _cursorIsArrow = true;
- CursorMan.showMouse(true);
+ _menu->setCommandsCallback(menuCommandsCallback, this);
- for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
- _patterns.push_back(fillPatterns[i]);
+ _menu->addStaticMenus(menuSubItems);
+ _menu->addMenuSubItem(kMenuAbout, _engine->_world->getAboutMenuItemName(), kMenuActionAbout);
- loadFonts();
+ _commandsMenuId = _menu->addMenuItem(_engine->_world->_commandsMenuName.c_str());
+ regenCommandsMenu();
- g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "wageCursor");
+ if (!_engine->_world->_weaponMenuDisabled) {
+ _weaponsMenuId = _menu->addMenuItem(_engine->_world->_weaponsMenuName.c_str());
+
+ regenWeaponsMenu();
+ } else {
+ _weaponsMenuId = -1;
+ }
+
+ _menu->calcDimensions();
- _menu = new Menu(this);
+ _sceneWindow = _wm.addWindow(false, false, false);
+ _sceneWindow->setCallback(sceneWindowCallback, this);
+
+ _consoleWindow = _wm.addWindow(true, true, true);
+ _consoleWindow->setCallback(consoleWindowCallback, this);
}
Gui::~Gui() {
_screen.free();
_console.free();
g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler);
- delete _menu;
}
void Gui::undrawCursor() {
@@ -198,82 +183,34 @@ void Gui::undrawCursor() {
_cursorOff = false;
}
-const Graphics::Font *Gui::getFont(const char *name, Graphics::FontManager::FontUsage fallback) {
- const Graphics::Font *font = 0;
-
- if (!_builtInFonts) {
- font = FontMan.getFontByName(name);
-
- if (!font)
- warning("Cannot load font %s", name);
- }
-
- if (_builtInFonts || !font)
- font = FontMan.getFontByUsage(fallback);
-
- return font;
-}
-
-const Graphics::Font *Gui::getTitleFont() {
- return getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
-}
-
-void Gui::drawDesktop() {
- // Draw desktop
- Common::Rect r(0, 0, _screen.w - 1, _screen.h - 1);
- Design::drawFilledRoundRect(&_screen, r, kDesktopArc, kColorBlack, _patterns, kPatternCheckers);
- g_system->copyRectToScreen(_screen.getPixels(), _screen.pitch, 0, 0, _screen.w, _screen.h);
-}
-
void Gui::draw() {
if (_engine->_isGameOver) {
- if (_menuDirty) {
- drawDesktop();
- _menu->render();
- }
-
- _menuDirty = false;
+ _wm.draw();
return;
}
- if (_scene != _engine->_world->_player->_currentScene || _sceneDirty) {
- _scene = _engine->_world->_player->_currentScene;
-
- drawDesktop();
+ if (!_engine->_world->_player->_currentScene)
+ return;
+ if (_scene != _engine->_world->_player->_currentScene) {
_sceneDirty = true;
- _consoleDirty = true;
- _menuDirty = true;
- _consoleFullRedraw = true;
- _scene->paint(&_screen, _scene->_designBounds->left, _scene->_designBounds->top);
+ _scene = _engine->_world->_player->_currentScene;
- _sceneArea.left = _scene->_designBounds->left + kBorderWidth - 2;
- _sceneArea.top = _scene->_designBounds->top + kBorderWidth - 2;
- _sceneArea.setWidth(_scene->_designBounds->width() - 2 * kBorderWidth);
- _sceneArea.setHeight(_scene->_designBounds->height() - 2 * kBorderWidth);
+ _sceneWindow->setDimensions(*_scene->_designBounds);
+ _sceneWindow->setTitle(_scene->_name);
+ _consoleWindow->setDimensions(*_scene->_textBounds);
- _consoleTextArea.left = _scene->_textBounds->left + kBorderWidth - 2;
- _consoleTextArea.top = _scene->_textBounds->top + kBorderWidth - 2;
- _consoleTextArea.setWidth(_scene->_textBounds->width() - 2 * kBorderWidth);
- _consoleTextArea.setHeight(_scene->_textBounds->height() - 2 * kBorderWidth);
+ _wm.setFullRefresh(true);
}
- if (_scene && (_bordersDirty || _sceneDirty))
- paintBorder(&_screen, _sceneArea, kWindowScene);
+ drawScene();
+ drawConsole();
- // Render console
- if (_consoleDirty || _consoleFullRedraw)
- renderConsole(&_screen, _consoleTextArea);
+ _wm.draw();
- if (_bordersDirty || _consoleDirty || _consoleFullRedraw)
- paintBorder(&_screen, _consoleTextArea, kWindowConsole);
-
- if (_menuDirty)
- _menu->render();
-
- if (_cursorDirty) {
+ if (_cursorDirty && _cursorRect.left < _screen.w && _cursorRect.bottom < _screen.h) {
g_system->copyRectToScreen(_screen.getBasePtr(_cursorRect.left, _cursorRect.top), _screen.pitch,
_cursorRect.left, _cursorRect.top, _cursorRect.width(), _cursorRect.height());
@@ -282,336 +219,141 @@ void Gui::draw() {
_sceneDirty = false;
_consoleDirty = false;
- _bordersDirty = false;
- _menuDirty = false;
_consoleFullRedraw = false;
}
-void Gui::drawBox(Graphics::Surface *g, int x, int y, int w, int h) {
- Common::Rect r(x, y, x + w + 1, y + h + 1);
-
- g->fillRect(r, kColorWhite);
- g->frameRect(r, kColorBlack);
-}
+void Gui::drawScene() {
+ if (!_sceneDirty)
+ return;
-void Gui::fillRect(Graphics::Surface *g, int x, int y, int w, int h) {
- Common::Rect r(x, y, x + w, y + h);
+ _scene->paint(_sceneWindow->getSurface(), 0, 0);
+ _sceneWindow->setDirty(true);
- g->fillRect(r, kColorBlack);
+ _sceneDirty = true;
+ _consoleDirty = true;
+ _menu->setDirty(true);
+ _consoleFullRedraw = true;
}
-#define ARROW_W 12
-#define ARROW_H 6
-const int arrowPixels[ARROW_H][ARROW_W] = {
- {0,0,0,0,0,1,1,0,0,0,0,0},
- {0,0,0,0,1,1,1,1,0,0,0,0},
- {0,0,0,1,1,1,1,1,1,0,0,0},
- {0,0,1,1,1,1,1,1,1,1,0,0},
- {0,1,1,1,1,1,1,1,1,1,1,0},
- {1,1,1,1,1,1,1,1,1,1,1,1}};
-
-void Gui::paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType) {
- bool active = false, scrollable = false, closeable = false, closeBoxPressed = false, drawTitle = false;
- const int size = kBorderWidth;
- int x = r.left - size;
- int y = r.top - size;
- int width = r.width() + 2 * size;
- int height = r.height() + 2 * size;
-
- switch (windowType) {
- case kWindowScene:
- active = _sceneIsActive;
- scrollable = false;
- closeable = _sceneIsActive;
- closeBoxPressed = false;
- drawTitle = true;
- break;
- case kWindowConsole:
- active = !_sceneIsActive;
- scrollable = true;
- closeable = !_sceneIsActive;
- closeBoxPressed = false;
- drawTitle = false;
- break;
- }
+static bool sceneWindowCallback(WindowClick click, Common::Event &event, void *g) {
+ Gui *gui = (Gui *)g;
- drawBox(g, x, y, size, size);
- drawBox(g, x + width - size - 1, y, size, size);
- drawBox(g, x + width - size - 1, y + height - size - 1, size, size);
- drawBox(g, x, y + height - size - 1, size, size);
- drawBox(g, x + size, y + 2, width - 2 * size - 1, size - 4);
- drawBox(g, x + size, y + height - size + 1, width - 2 * size - 1, size - 4);
- drawBox(g, x + 2, y + size, size - 4, height - 2 * size - 1);
- drawBox(g, x + width - size + 1, y + size, size - 4, height - 2 * size - 1);
-
- if (active) {
- fillRect(g, x + size, y + 5, width - 2 * size - 1, 8);
- fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8);
- fillRect(g, x + 5, y + size, 8, height - 2 * size - 1);
- if (!scrollable) {
- fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1);
- } else {
- int x1 = x + width - 15;
- int y1 = y + size + 1;
- for (int yy = 0; yy < ARROW_H; yy++) {
- for (int xx = 0; xx < ARROW_W; xx++) {
- if (arrowPixels[yy][xx] != 0) {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorBlack);
- } else {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorWhite);
- }
- }
- }
- fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2);
- y1 += height - 2 * size - ARROW_H - 2;
- for (int yy = 0; yy < ARROW_H; yy++) {
- for (int xx = 0; xx < ARROW_W; xx++) {
- if (arrowPixels[ARROW_H - yy - 1][xx] != 0) {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorBlack);
- } else {
- g->hLine(x1 + xx, y1 + yy, x1 + xx, kColorWhite);
- }
- }
- }
- }
- if (closeable) {
- if (closeBoxPressed) {
- fillRect(g, x + 6, y + 6, 6, 6);
- } else {
- drawBox(g, x + 5, y + 5, 7, 7);
- }
- }
- }
+ return gui->processSceneEvents(click, event);
+}
- if (drawTitle) {
- const Graphics::Font *font = getTitleFont();
- int yOff = _builtInFonts ? 3 : 1;
+bool Gui::processSceneEvents(WindowClick click, Common::Event &event) {
+ if (click == kBorderInner && event.type == Common::EVENT_LBUTTONUP) {
+ Designed *obj = _scene->lookUpEntity(event.mouse.x - _sceneWindow->getDimensions().left,
+ event.mouse.y - _sceneWindow->getDimensions().top);
- int w = font->getStringWidth(_scene->_name) + 10;
- int maxWidth = width - size * 2 - 7;
- if (w > maxWidth)
- w = maxWidth;
- drawBox(g, x + (width - w) / 2, y, w, size);
- font->drawString(g, _scene->_name, x + (width - w) / 2 + 5, y + yOff, w, kColorBlack);
- }
+ if (obj != nullptr)
+ _engine->processTurn(NULL, obj);
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
+ return true;
}
- if (x + width > _screen.w)
- width = _screen.w - x;
- if (y + height > _screen.h)
- height = _screen.h - y;
- g_system->copyRectToScreen(g->getBasePtr(x, y), g->pitch, x, y, width, height);
+ return false;
}
-void Gui::loadFonts() {
- Common::Archive *dat;
-
- dat = Common::makeZipArchive("wage.dat");
-
- if (!dat) {
- warning("Could not find wage.dat. Falling back to built-in fonts");
- _builtInFonts = true;
-
+// Render console
+void Gui::drawConsole() {
+ if (!_consoleDirty && !_consoleFullRedraw && !_sceneDirty)
return;
- }
-
- Common::ArchiveMemberList list;
- dat->listMembers(list);
-
- for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
- Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
-
- Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream);
-
- delete stream;
- Common::String fontName = (*it)->getName();
-
- // Trim the .bdf extension
- for (int i = fontName.size() - 1; i >= 0; --i) {
- if (fontName[i] == '.') {
- while ((uint)i < fontName.size()) {
- fontName.deleteLastChar();
- }
- break;
- }
- }
-
- FontMan.assignFontToName(fontName, font);
-
- debug(2, " %s", fontName.c_str());
- }
+ renderConsole(_consoleWindow->getSurface(), Common::Rect(kBorderWidth - 2, kBorderWidth - 2,
+ _consoleWindow->getDimensions().width(), _consoleWindow->getDimensions().height()));
+ _consoleWindow->setDirty(true);
+}
- _builtInFonts = false;
+static bool consoleWindowCallback(WindowClick click, Common::Event &event, void *g) {
+ Gui *gui = (Gui *)g;
- delete dat;
+ return gui->processConsoleEvents(click, event);
}
+////////////////
+// Menu stuff
+////////////////
void Gui::regenCommandsMenu() {
- _menu->regenCommandsMenu();
+ _menu->createSubMenuFromString(_commandsMenuId, _engine->_world->_commandsMenu.c_str());
}
void Gui::regenWeaponsMenu() {
- _menu->regenWeaponsMenu();
-}
-
-void Gui::processMenuShortCut(byte flags, uint16 ascii) {
- _menu->processMenuShortCut(flags, ascii);
-}
-
-void Gui::mouseMove(int x, int y) {
- if (_menu->_menuActivated) {
- if (_menu->mouseMove(x, y))
- _menuDirty = true;
-
+ if (_engine->_world->_weaponMenuDisabled)
return;
- }
- if (_inTextSelection) {
- updateTextSelection(x, y);
- return;
- }
+ _menu->clearSubMenu(_weaponsMenuId);
- if (_consoleTextArea.contains(x, y)) {
- if (_cursorIsArrow) {
- CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3);
- _cursorIsArrow = false;
- }
- } else if (_cursorIsArrow == false) {
- CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
- _cursorIsArrow = true;
- }
-}
-
-void Gui::pushArrowCursor() {
- CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
-}
-
-void Gui::popCursor() {
- CursorMan.popCursor();
-}
-
-Designed *Gui::mouseUp(int x, int y) {
- if (_menu->_menuActivated) {
- if (_menu->mouseRelease(x, y)) {
- _sceneDirty = true;
- _consoleDirty = true;
- _bordersDirty = true;
- _menuDirty = true;
- }
-
- return NULL;
- }
-
- if (_inTextSelection) {
- _inTextSelection = false;
+ Chr *player = _engine->_world->_player;
+ ObjArray *weapons = player->getWeapons(true);
- if (_selectionEndY == -1 ||
- (_selectionEndX == _selectionStartX && _selectionEndY == _selectionStartY)) {
- _selectionStartY = _selectionEndY = -1;
- _consoleFullRedraw = true;
- _menu->enableCommand(kMenuEdit, kMenuActionCopy, false);
- } else {
- _menu->enableCommand(kMenuEdit, kMenuActionCopy, true);
+ bool empty = true;
- bool cutAllowed = false;
+ for (uint i = 0; i < weapons->size(); i++) {
+ Obj *obj = (*weapons)[i];
+ if (obj->_type == Obj::REGULAR_WEAPON ||
+ obj->_type == Obj::THROW_WEAPON ||
+ obj->_type == Obj::MAGICAL_OBJECT) {
+ Common::String command(obj->_operativeVerb);
+ command += " ";
+ command += obj->_name;
- if (_selectionStartY == _selectionEndY && _selectionStartY == (int)_lines.size() - 1)
- cutAllowed = true;
+ _menu->addMenuSubItem(_weaponsMenuId, command.c_str(), kMenuActionCommand, 0, 0, true);
- _menu->enableCommand(kMenuEdit, kMenuActionCut, cutAllowed);
- _menu->enableCommand(kMenuEdit, kMenuActionClear, cutAllowed);
+ empty = false;
}
}
+ delete weapons;
- if (_sceneArea.contains(x, y)) {
- if (!_sceneIsActive) {
- _sceneIsActive = true;
- _bordersDirty = true;
- }
-
- for (ObjList::const_iterator it = _scene->_objs.begin(); it != _scene->_objs.end(); ++it) {
- if ((*it)->_design->isPointOpaque(x - _sceneArea.left + kBorderWidth, y - _sceneArea.top + kBorderWidth))
- return *it;
- }
-
- for (ChrList::const_iterator it = _scene->_chrs.begin(); it != _scene->_chrs.end(); ++it) {
- if ((*it)->_design->isPointOpaque(x - _sceneArea.left + kBorderWidth, y - _sceneArea.top + kBorderWidth))
- return *it;
- }
- } else if (_consoleTextArea.contains(x, y)) {
- if (_sceneIsActive) {
- _sceneIsActive = false;
- _bordersDirty = true;
- }
- }
-
- return NULL;
-}
-
-void Gui::mouseDown(int x, int y) {
- if (_menu->mouseClick(x, y)) {
- _menuDirty = true;
- } else if (_consoleTextArea.contains(x, y)) {
- startMarking(x, y);
- }
+ if (empty)
+ _menu->addMenuSubItem(_weaponsMenuId, "You have no weapons", 0, 0, 0, false);
}
-int Gui::calcTextX(int x, int textLine) {
- const Graphics::Font *font = getConsoleFont();
-
- if ((uint)textLine >= _lines.size())
- return 0;
-
- Common::String str = _lines[textLine];
-
- x -= _consoleTextArea.left;
-
- for (int i = str.size(); i >= 0; i--) {
- if (font->getStringWidth(str) < x) {
- return i;
- }
-
- str.deleteLastChar();
- }
-
- return 0;
+bool Gui::processEvent(Common::Event &event) {
+ return _wm.processEvent(event);
}
-int Gui::calcTextY(int y) {
- y -= _consoleTextArea.top;
-
- if (y < 0)
- y = 0;
-
- const int firstLine = _scrollPos / _consoleLineHeight;
- int textLine = (y - _scrollPos % _consoleLineHeight) / _consoleLineHeight + firstLine;
+void menuCommandsCallback(int action, Common::String &text, void *data) {
+ Gui *g = (Gui *)data;
- return textLine;
+ g->executeMenuCommand(action, text);
}
-void Gui::startMarking(int x, int y) {
- _selectionStartY = calcTextY(y);
- _selectionStartX = calcTextX(x, _selectionStartY);
-
- _selectionEndY = -1;
+void Gui::executeMenuCommand(int action, Common::String &text) {
+ switch(action) {
+ case kMenuActionAbout:
+ case kMenuActionNew:
+ case kMenuActionOpen:
+ case kMenuActionClose:
+ case kMenuActionSave:
+ case kMenuActionSaveAs:
+ case kMenuActionRevert:
+ case kMenuActionQuit:
+
+ case kMenuActionUndo:
+ actionUndo();
+ break;
+ case kMenuActionCut:
+ actionCut();
+ break;
+ case kMenuActionCopy:
+ actionCopy();
+ break;
+ case kMenuActionPaste:
+ actionPaste();
+ break;
+ case kMenuActionClear:
+ actionClear();
+ break;
- _inTextSelection = true;
-}
+ case kMenuActionCommand:
+ _engine->processTurn(&text, NULL);
+ break;
-void Gui::updateTextSelection(int x, int y) {
- _selectionEndY = calcTextY(y);
- _selectionEndX = calcTextX(x, _selectionEndY);
+ default:
+ warning("Unknown action: %d", action);
- _consoleFullRedraw = true;
+ }
}
} // End of namespace Wage
diff --git a/engines/wage/gui.h b/engines/wage/gui.h
index 61f8c31a07..ba1bb5ef3b 100644
--- a/engines/wage/gui.h
+++ b/engines/wage/gui.h
@@ -50,40 +50,23 @@
#include "common/str-array.h"
#include "graphics/font.h"
-#include "graphics/fontman.h"
-#include "graphics/surface.h"
+#include "graphics/managed_surface.h"
+#include "common/events.h"
#include "common/rect.h"
+#include "wage/macwindow.h"
+#include "wage/macwindowmanager.h"
+
namespace Wage {
class Menu;
-
-enum WindowType {
- kWindowScene,
- kWindowConsole
-};
+class Scene;
+class WageEngine;
enum {
- kMenuHeight = 20,
- kMenuLeftMargin = 7,
- kMenuSpacing = 13,
- kMenuPadding = 16,
- kMenuDropdownPadding = 14,
- kMenuDropdownItemHeight = 16,
- kMenuItemHeight = 20,
- kBorderWidth = 17,
- kDesktopArc = 7,
- kComponentsPadding = 10,
kCursorHeight = 12
};
-enum {
- kPatternSolid = 1,
- kPatternStripes = 2,
- kPatternCheckers = 3,
- kPatternCheckers2 = 4
-};
-
class Gui {
public:
Gui(WageEngine *engine);
@@ -92,17 +75,12 @@ public:
void draw();
void appendText(const char *str);
void clearOutput();
- void mouseMove(int x, int y);
- void mouseDown(int x, int y);
- Designed *mouseUp(int x, int y);
+ bool processEvent(Common::Event &event);
+
void drawInput();
void setSceneDirty() { _sceneDirty = true; }
- const Graphics::Font *getFont(const char *name, Graphics::FontManager::FontUsage fallback);
void regenCommandsMenu();
void regenWeaponsMenu();
- void processMenuShortCut(byte flags, uint16 ascii);
- void pushArrowCursor();
- void popCursor();
void actionCopy();
void actionPaste();
@@ -113,14 +91,15 @@ public:
void disableAllMenus();
void enableNewGameMenus();
+ bool processSceneEvents(WindowClick click, Common::Event &event);
+ bool processConsoleEvents(WindowClick click, Common::Event &event);
+ void executeMenuCommand(int action, Common::String &text);
+
private:
+ void drawScene();
+ void drawConsole();
void undrawCursor();
- void drawDesktop();
- void paintBorder(Graphics::Surface *g, Common::Rect &r, WindowType windowType);
- void renderConsole(Graphics::Surface *g, Common::Rect &r);
- void drawBox(Graphics::Surface *g, int x, int y, int w, int h);
- void fillRect(Graphics::Surface *g, int x, int y, int w, int h);
- void loadFonts();
+ void renderConsole(Graphics::ManagedSurface *g, const Common::Rect &r);
void flowText(Common::String &str);
const Graphics::Font *getConsoleFont();
const Graphics::Font *getTitleFont();
@@ -130,29 +109,27 @@ private:
void updateTextSelection(int x, int y);
public:
- Graphics::Surface _screen;
+ Graphics::ManagedSurface _screen;
int _cursorX, _cursorY;
bool _cursorState;
- Common::Rect _consoleTextArea;
- bool _builtInFonts;
WageEngine *_engine;
- Patterns _patterns;
-
bool _cursorDirty;
Common::Rect _cursorRect;
bool _cursorOff;
- bool _menuDirty;
+ Scene *_scene;
+
+ MacWindowManager _wm;
+ MacWindow *_sceneWindow;
+ MacWindow *_consoleWindow;
private:
- Graphics::Surface _console;
+ Graphics::ManagedSurface _console;
Menu *_menu;
- Scene *_scene;
bool _sceneDirty;
bool _consoleDirty;
- bool _bordersDirty;
Common::StringArray _out;
Common::StringArray _lines;
@@ -161,10 +138,6 @@ private:
uint _consoleNumLines;
bool _consoleFullRedraw;
- Common::Rect _sceneArea;
- bool _sceneIsActive;
- bool _cursorIsArrow;
-
bool _inTextSelection;
int _selectionStartX;
int _selectionStartY;
@@ -175,6 +148,9 @@ private:
Common::String _undobuffer;
int _inputTextLineNum;
+
+ int _commandsMenuId;
+ int _weaponsMenuId;
};
} // End of namespace Wage
diff --git a/engines/wage/menu.cpp b/engines/wage/macmenu.cpp
index 48f16421b5..ed5f5070ff 100644
--- a/engines/wage/menu.cpp
+++ b/engines/wage/macmenu.cpp
@@ -48,15 +48,25 @@
#include "common/system.h"
#include "common/keyboard.h"
-#include "wage/wage.h"
-#include "wage/entities.h"
-#include "wage/design.h"
-#include "wage/gui.h"
-#include "wage/menu.h"
-#include "wage/world.h"
+#include "graphics/primitives.h"
+#include "graphics/font.h"
+
+#include "wage/macwindowmanager.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
namespace Wage {
+enum {
+ kMenuHeight = 20,
+ kMenuLeftMargin = 7,
+ kMenuSpacing = 13,
+ kMenuPadding = 16,
+ kMenuDropdownPadding = 14,
+ kMenuDropdownItemHeight = 16,
+ kMenuItemHeight = 20
+};
+
struct MenuSubItem {
Common::String text;
int action;
@@ -79,66 +89,65 @@ struct MenuItem {
MenuItem(const char *n) : name(n) {}
};
-struct MenuData {
- int menunum;
- const char *title;
- int action;
- byte shortcut;
- bool enabled;
-} static const menuSubItems[] = {
- { kMenuFile, "New", kMenuActionNew, 0, false },
- { kMenuFile, "Open...", kMenuActionOpen, 0, false },
- { kMenuFile, "Close", kMenuActionClose, 0, true },
- { kMenuFile, "Save", kMenuActionSave, 0, false },
- { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true },
- { kMenuFile, "Revert", kMenuActionRevert, 0, false },
- { kMenuFile, "Quit", kMenuActionQuit, 0, true },
-
- { kMenuEdit, "Undo", kMenuActionUndo, 'Z', false },
- { kMenuEdit, NULL, 0, 0, false },
- { kMenuEdit, "Cut", kMenuActionCut, 'K', false },
- { kMenuEdit, "Copy", kMenuActionCopy, 'C', false },
- { kMenuEdit, "Paste", kMenuActionPaste, 'V', false },
- { kMenuEdit, "Clear", kMenuActionClear, 'B', false },
-
- { 0, NULL, 0, 0, false }
-};
+Menu::Menu(int id, const Common::Rect &bounds, MacWindowManager *wm)
+ : BaseMacWindow(id, false, wm) {
+ _font = getMenuFont();
-Menu::Menu(Gui *gui) : _gui(gui) {
- assert(_gui->_engine);
- assert(_gui->_engine->_world);
+ _screen.create(bounds.width(), bounds.height(), Graphics::PixelFormat::createFormatCLUT8());
- _font = getMenuFont();
+ _bbox.left = 0;
+ _bbox.top = 0;
+ _bbox.right = _screen.w;
+ _bbox.bottom = kMenuHeight;
+
+ _menuActivated = false;
+ _activeItem = -1;
+ _activeSubItem = -1;
+
+ _ccallback = NULL;
+ _cdata = NULL;
+
+ _tempSurface.create(_screen.w, _font->getFontHeight(), Graphics::PixelFormat::createFormatCLUT8());
+}
+
+Menu::~Menu() {
+ for (uint i = 0; i < _items.size(); i++) {
+ for (uint j = 0; j < _items[i]->subitems.size(); j++)
+ delete _items[i]->subitems[j];
+ delete _items[i];
+ }
+}
- MenuItem *about = new MenuItem(_gui->_builtInFonts ? "\xa9" : "\xf0"); // (c) Symbol as the most resembling apple
+void Menu::addStaticMenus(const MenuData *data) {
+ MenuItem *about = new MenuItem(_wm->hasBuiltInFonts() ? "\xa9" : "\xf0"); // (c) Symbol as the most resembling apple
_items.push_back(about);
- _items[0]->subitems.push_back(new MenuSubItem(_gui->_engine->_world->getAboutMenuItemName(), kMenuActionAbout));
- MenuItem *file = new MenuItem("File");
- _items.push_back(file);
+ for (int i = 0; data[i].menunum; i++) {
+ const MenuData *m = &data[i];
- MenuItem *edit = new MenuItem("Edit");
- _items.push_back(edit);
+ if (m->menunum == kMenuHighLevel) {
+ MenuItem *item = new MenuItem(m->title);
+ _items.push_back(item);
- for (int i = 0; menuSubItems[i].menunum; i++) {
- const MenuData *m = &menuSubItems[i];
+ continue;
+ }
_items[m->menunum]->subitems.push_back(new MenuSubItem(m->title, m->action, 0, m->shortcut, m->enabled));
}
+}
- _commands = new MenuItem(_gui->_engine->_world->_commandsMenuName.c_str());
- _items.push_back(_commands);
- regenCommandsMenu();
-
- _weapons = NULL;
+int Menu::addMenuItem(const char *name) {
+ MenuItem *i = new MenuItem(name);
+ _items.push_back(i);
- if (!_gui->_engine->_world->_weaponMenuDisabled) {
- _weapons = new MenuItem(_gui->_engine->_world->_weaponsMenuName.c_str());
- _items.push_back(_weapons);
+ return _items.size() - 1;
+}
- regenWeaponsMenu();
- }
+void Menu::addMenuSubItem(int id, const char *text, int action, int style, char shortcut, bool enabled) {
+ _items[id]->subitems.push_back(new MenuSubItem(text, action, style, shortcut, enabled));
+}
+void Menu::calcDimensions() {
// Calculate menu dimensions
int y = 1;
int x = 18;
@@ -150,47 +159,29 @@ Menu::Menu(Gui *gui) : _gui(gui) {
_items[i]->bbox.left = x - kMenuLeftMargin;
_items[i]->bbox.top = y;
_items[i]->bbox.right = x + w + kMenuSpacing - kMenuLeftMargin;
- _items[i]->bbox.bottom = y + _font->getFontHeight() + (_gui->_builtInFonts ? 3 : 2);
+ _items[i]->bbox.bottom = y + _font->getFontHeight() + (_wm->hasBuiltInFonts() ? 3 : 2);
}
calcMenuBounds(_items[i]);
x += w + kMenuSpacing;
}
-
- _bbox.left = 0;
- _bbox.top = 0;
- _bbox.right = _gui->_screen.w - 1;
- _bbox.bottom = kMenuHeight - 1;
-
- _menuActivated = false;
- _activeItem = -1;
- _activeSubItem = -1;
-
- _screenCopy.create(_gui->_screen.w, _gui->_screen.h, Graphics::PixelFormat::createFormatCLUT8());
- _tempSurface.create(_gui->_screen.w, _font->getFontHeight(), Graphics::PixelFormat::createFormatCLUT8());
-}
-
-Menu::~Menu() {
- for (uint i = 0; i < _items.size(); i++) {
- for (uint j = 0; j < _items[i]->subitems.size(); j++)
- delete _items[i]->subitems[j];
- delete _items[i];
- }
}
-void Menu::regenCommandsMenu() {
- for (uint j = 0; j < _commands->subitems.size(); j++)
- delete _commands->subitems[j];
+void Menu::clearSubMenu(int id) {
+ MenuItem *menu = _items[id];
- _commands->subitems.clear();
+ for (uint j = 0; j < menu->subitems.size(); j++)
+ delete menu->subitems[j];
- createCommandsMenu(_commands);
- calcMenuBounds(_commands);
+ menu->subitems.clear();
}
-void Menu::createCommandsMenu(MenuItem *menu) {
- Common::String string(_gui->_engine->_world->_commandsMenu);
+void Menu::createSubMenuFromString(int id, const char *str) {
+ clearSubMenu(id);
+
+ MenuItem *menu = _items[id];
+ Common::String string(str);
Common::String item;
@@ -206,10 +197,10 @@ void Menu::createCommandsMenu(MenuItem *menu) {
char shortcut = 0;
const char *shortPtr = strrchr(item.c_str(), '/');
if (shortPtr != NULL) {
- if (strlen(shortPtr) == 2) {
+ if (strlen(shortPtr) >= 2) {
shortcut = shortPtr[1];
- item.deleteLastChar();
- item.deleteLastChar();
+ item.deleteChar(shortPtr - item.c_str());
+ item.deleteChar(shortPtr - item.c_str());
} else {
error("Unexpected shortcut: '%s', item '%s' in menu '%s'", shortPtr, item.c_str(), string.c_str());
}
@@ -253,45 +244,12 @@ void Menu::createCommandsMenu(MenuItem *menu) {
item.clear();
}
-}
-
-void Menu::regenWeaponsMenu() {
- if (_gui->_engine->_world->_weaponMenuDisabled)
- return;
-
- for (uint j = 0; j < _weapons->subitems.size(); j++)
- delete _weapons->subitems[j];
-
- _weapons->subitems.clear();
-
- createWeaponsMenu(_weapons);
- calcMenuBounds(_weapons);
-}
-
-void Menu::createWeaponsMenu(MenuItem *menu) {
- Chr *player = _gui->_engine->_world->_player;
- ObjArray *weapons = player->getWeapons(true);
-
- for (uint i = 0; i < weapons->size(); i++) {
- Obj *obj = (*weapons)[i];
- if (obj->_type == Obj::REGULAR_WEAPON ||
- obj->_type == Obj::THROW_WEAPON ||
- obj->_type == Obj::MAGICAL_OBJECT) {
- Common::String command(obj->_operativeVerb);
- command += " ";
- command += obj->_name;
-
- menu->subitems.push_back(new MenuSubItem(command.c_str(), kMenuActionCommand, 0, 0, true));
- }
- }
- delete weapons;
- if (menu->subitems.empty())
- menu->subitems.push_back(new MenuSubItem("You have no weapons", 0, 0, 0, false));
+ calcMenuBounds(menu);
}
const Graphics::Font *Menu::getMenuFont() {
- return _gui->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+ return _wm->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
}
const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) {
@@ -299,7 +257,7 @@ const char *Menu::getAcceleratorString(MenuSubItem *item, const char *prefix) {
*res = 0;
if (item->shortcut != 0)
- sprintf(res, "%s%c%c", prefix, (_gui->_builtInFonts ? '^' : '\x11'), item->shortcut);
+ sprintf(res, "%s%c%c", prefix, (_wm->hasBuiltInFonts() ? '^' : '\x11'), item->shortcut);
return res;
}
@@ -338,14 +296,35 @@ void Menu::calcMenuBounds(MenuItem *menu) {
menu->subbbox.bottom = y2;
}
-void Menu::render() {
+static void drawPixelPlain(int x, int y, int color, void *data) {
+ Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h)
+ *((byte *)surface->getBasePtr(x, y)) = (byte)color;
+}
+
+static void drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color) {
+ Graphics::drawRoundRect(rect, arc, color, true, drawPixelPlain, surface);
+}
+
+bool Menu::draw(Graphics::ManagedSurface *g, bool forceRedraw) {
Common::Rect r(_bbox);
- Design::drawFilledRoundRect(&_gui->_screen, r, kDesktopArc, kColorWhite, _gui->_patterns, kPatternSolid);
+ if (!_contentIsDirty && !forceRedraw)
+ return false;
+
+ _contentIsDirty = false;
+
+ _screen.clear(kColorGreen);
+
+ drawFilledRoundRect(&_screen, r, kDesktopArc, kColorWhite);
r.top = 7;
- Design::drawFilledRect(&_gui->_screen, r, kColorWhite, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(r, kColorWhite);
r.top = kMenuHeight - 1;
- Design::drawFilledRect(&_gui->_screen, r, kColorBlack, _gui->_patterns, kPatternSolid);
+ r.bottom++;
+ _screen.fillRect(r, kColorGreen);
+ r.bottom--;
+ _screen.fillRect(r, kColorBlack);
for (uint i = 0; i < _items.size(); i++) {
int color = kColorBlack;
@@ -355,19 +334,24 @@ void Menu::render() {
Common::Rect hbox = it->bbox;
hbox.left -= 1;
- hbox.right += 2;
+ hbox.right += 3;
+ hbox.bottom += 1;
- Design::drawFilledRect(&_gui->_screen, hbox, kColorBlack, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(hbox, kColorBlack);
color = kColorWhite;
if (!it->subitems.empty())
renderSubmenu(it);
}
- _font->drawString(&_gui->_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_gui->_builtInFonts ? 2 : 1), it->bbox.width(), color);
+ _font->drawString(&_screen, it->name, it->bbox.left + kMenuLeftMargin, it->bbox.top + (_wm->hasBuiltInFonts() ? 2 : 1), it->bbox.width(), color);
}
- g_system->copyRectToScreen(_gui->_screen.getPixels(), _gui->_screen.pitch, 0, 0, _gui->_screen.w, kMenuHeight);
+ g->transBlitFrom(_screen, kColorGreen);
+
+ g_system->copyRectToScreen(g->getPixels(), g->pitch, 0, 0, g->w, g->h);
+
+ return true;
}
void Menu::renderSubmenu(MenuItem *menu) {
@@ -376,10 +360,12 @@ void Menu::renderSubmenu(MenuItem *menu) {
if (r->width() == 0 || r->height() == 0)
return;
- Design::drawFilledRect(&_gui->_screen, *r, kColorWhite, _gui->_patterns, kPatternSolid);
- Design::drawRect(&_gui->_screen, *r, 1, kColorBlack, _gui->_patterns, kPatternSolid);
- Design::drawVLine(&_gui->_screen, r->right + 1, r->top + 3, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid);
- Design::drawHLine(&_gui->_screen, r->left + 3, r->right + 1, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(*r, kColorWhite);
+ _screen.frameRect(*r, kColorBlack);
+ _screen.vLine(r->right, r->top + 3, r->bottom + 1, kColorBlack);
+ _screen.vLine(r->right + 1, r->top + 3, r->bottom + 1, kColorBlack);
+ _screen.hLine(r->left + 3, r->bottom, r->right + 1, kColorBlack);
+ _screen.hLine(r->left + 3, r->bottom + 1, r->right + 1, kColorBlack);
int x = r->left + kMenuDropdownPadding;
int y = r->top + 1;
@@ -391,13 +377,13 @@ void Menu::renderSubmenu(MenuItem *menu) {
int color = kColorBlack;
if (i == (uint)_activeSubItem && !text.empty() && menu->subitems[i]->enabled) {
color = kColorWhite;
- Common::Rect trect(r->left, y - (_gui->_builtInFonts ? 1 : 0), r->right, y + _font->getFontHeight());
+ Common::Rect trect(r->left, y - (_wm->hasBuiltInFonts() ? 1 : 0), r->right, y + _font->getFontHeight());
- Design::drawFilledRect(&_gui->_screen, trect, kColorBlack, _gui->_patterns, kPatternSolid);
+ _screen.fillRect(trect, kColorBlack);
}
if (!text.empty()) {
- Graphics::Surface *s = &_gui->_screen;
+ Graphics::ManagedSurface *s = &_screen;
int tx = x, ty = y;
if (!menu->subitems[i]->enabled) {
@@ -406,7 +392,7 @@ void Menu::renderSubmenu(MenuItem *menu) {
ty = 0;
accelX -= x;
- _tempSurface.fillRect(Common::Rect(0, 0, _tempSurface.w, _tempSurface.h), kColorGreen);
+ _tempSurface.clear(kColorGreen);
}
_font->drawString(s, text, tx, ty, r->width(), color);
@@ -419,8 +405,8 @@ void Menu::renderSubmenu(MenuItem *menu) {
// fake it here
for (int ii = 0; ii < _tempSurface.h; ii++) {
const byte *src = (const byte *)_tempSurface.getBasePtr(0, ii);
- byte *dst = (byte *)_gui->_screen.getBasePtr(x, y+ii);
- byte pat = _gui->_patterns[kPatternCheckers2 - 1][ii % 8];
+ byte *dst = (byte *)_screen.getBasePtr(x, y+ii);
+ byte pat = _wm->getPatterns()[kPatternCheckers2 - 1][ii % 8];
for (int j = 0; j < r->width(); j++) {
if (*src != kColorGreen && (pat & (1 << (7 - (x + j) % 8))))
*dst = *src;
@@ -430,20 +416,51 @@ void Menu::renderSubmenu(MenuItem *menu) {
}
}
} else { // Delimiter
- Design::drawHLine(&_gui->_screen, r->left + 1, r->right - 1, y + kMenuDropdownItemHeight / 2, 1, kColorBlack, _gui->_patterns, kPatternStripes);
+ bool flip = r->left & 2;
+ byte *ptr = (byte *)_screen.getBasePtr(r->left + 1, y + kMenuDropdownItemHeight / 2);
+ for (int xx = r->left + 1; xx <= r->right - 1; xx++, ptr++) {
+ *ptr = flip ? kColorBlack : kColorWhite;
+ flip = !flip;
+ }
}
y += kMenuDropdownItemHeight;
}
- g_system->copyRectToScreen(_gui->_screen.getBasePtr(r->left, r->top), _gui->_screen.pitch, r->left, r->top, r->width() + 3, r->height() + 3);
+ _contentIsDirty = true;
+ //g_system->copyRectToScreen(_screen.getBasePtr(r->left, r->top), _screen.pitch, r->left, r->top, r->width() + 2, r->height() + 2);
+}
+
+bool Menu::processEvent(Common::Event &event) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ return keyEvent(event);
+ case Common::EVENT_LBUTTONDOWN:
+ return mouseClick(event.mouse.x, event.mouse.y);
+ case Common::EVENT_LBUTTONUP:
+ return mouseRelease(event.mouse.x, event.mouse.y);
+ case Common::EVENT_MOUSEMOVE:
+ return mouseMove(event.mouse.x, event.mouse.y);
+ default:
+ return false;
+ }
+}
+
+bool Menu::keyEvent(Common::Event &event) {
+ if (event.type != Common::EVENT_KEYDOWN)
+ return false;
+
+ if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
+ if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
+ return processMenuShortCut(event.kbd.flags, event.kbd.ascii);
+ }
+ }
+
+ return false;
}
bool Menu::mouseClick(int x, int y) {
if (_bbox.contains(x, y)) {
- if (!_menuActivated)
- _screenCopy.copyFrom(_gui->_screen);
-
for (uint i = 0; i < _items.size(); i++)
if (_items[i]->bbox.contains(x, y)) {
if ((uint)_activeItem == i)
@@ -454,14 +471,15 @@ bool Menu::mouseClick(int x, int y) {
r.right += 3;
r.bottom += 3;
- _gui->_screen.copyRectToSurface(_screenCopy, r.left, r.top, r);
- g_system->copyRectToScreen(_gui->_screen.getBasePtr(r.left, r.top), _gui->_screen.pitch, r.left, r.top, r.width() + 1, r.height() + 1);
+ _wm->setFullRefresh(true);
}
_activeItem = i;
_activeSubItem = -1;
_menuActivated = true;
+ _contentIsDirty = true;
+
return true;
}
} else if (_menuActivated && _items[_activeItem]->subbbox.contains(x, y)) {
@@ -472,11 +490,13 @@ bool Menu::mouseClick(int x, int y) {
_activeSubItem = numSubItem;
renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
}
} else if (_menuActivated && _activeItem != -1) {
_activeSubItem = -1;
renderSubmenu(_items[_activeItem]);
+ _contentIsDirty = true;
}
return false;
@@ -495,77 +515,49 @@ bool Menu::mouseRelease(int x, int y) {
_menuActivated = false;
if (_activeItem != -1 && _activeSubItem != -1 && _items[_activeItem]->subitems[_activeSubItem]->enabled)
- executeCommand(_items[_activeItem]->subitems[_activeSubItem]);
+ (*_ccallback)(_items[_activeItem]->subitems[_activeSubItem]->action,
+ _items[_activeItem]->subitems[_activeSubItem]->text, _cdata);
_activeItem = -1;
_activeSubItem = -1;
+ _wm->setFullRefresh(true);
+
return true;
}
return false;
}
-void Menu::executeCommand(MenuSubItem *subitem) {
- switch(subitem->action) {
- case kMenuActionAbout:
- case kMenuActionNew:
- case kMenuActionOpen:
- case kMenuActionClose:
- case kMenuActionSave:
- case kMenuActionSaveAs:
- case kMenuActionRevert:
- case kMenuActionQuit:
-
- case kMenuActionUndo:
- _gui->actionUndo();
- break;
- case kMenuActionCut:
- _gui->actionCut();
- break;
- case kMenuActionCopy:
- _gui->actionCopy();
- break;
- case kMenuActionPaste:
- _gui->actionPaste();
- break;
- case kMenuActionClear:
- _gui->actionClear();
- break;
-
- case kMenuActionCommand:
- _gui->_engine->processTurn(&subitem->text, NULL);
- break;
-
- default:
- warning("Unknown action: %d", subitem->action);
-
- }
-}
-
-void Menu::processMenuShortCut(byte flags, uint16 ascii) {
+bool Menu::processMenuShortCut(byte flags, uint16 ascii) {
ascii = tolower(ascii);
if (flags & (Common::KBD_CTRL | Common::KBD_META)) {
for (uint i = 0; i < _items.size(); i++)
for (uint j = 0; j < _items[i]->subitems.size(); j++)
if (_items[i]->subitems[j]->enabled && tolower(_items[i]->subitems[j]->shortcut) == ascii) {
- executeCommand(_items[i]->subitems[j]);
- break;
+ (*_ccallback)(_items[i]->subitems[j]->action, _items[i]->subitems[j]->text, _cdata);
+ return true;
}
}
+
+ return false;
}
void Menu::enableCommand(int menunum, int action, bool state) {
for (uint i = 0; i < _items[menunum]->subitems.size(); i++)
if (_items[menunum]->subitems[i]->action == action)
_items[menunum]->subitems[i]->enabled = state;
+
+ _contentIsDirty = true;
}
void Menu::disableAllMenus() {
for (uint i = 1; i < _items.size(); i++) // Leave About menu on
for (uint j = 0; j < _items[i]->subitems.size(); j++)
_items[i]->subitems[j]->enabled = false;
+
+ _contentIsDirty = true;
}
} // End of namespace Wage
diff --git a/engines/wage/menu.h b/engines/wage/macmenu.h
index 3550356bc6..e73e4c48a9 100644
--- a/engines/wage/menu.h
+++ b/engines/wage/macmenu.h
@@ -45,8 +45,8 @@
*
*/
-#ifndef WAGE_MENU_H
-#define WAGE_MENU_H
+#ifndef WAGE_MACMENU_H
+#define WAGE_MACMENU_H
namespace Wage {
@@ -64,6 +64,7 @@ enum {
};
enum {
+ kMenuHighLevel = -1,
kMenuAbout = 0,
kMenuFile = 1,
kMenuEdit = 2,
@@ -90,29 +91,43 @@ enum {
kMenuActionCommand
};
-class Menu {
+struct MenuData {
+ int menunum;
+ const char *title;
+ int action;
+ byte shortcut;
+ bool enabled;
+};
+
+class Menu : public BaseMacWindow {
public:
- Menu(Gui *gui);
+ Menu(int id, const Common::Rect &bounds, MacWindowManager *wm);
~Menu();
- void render();
- bool mouseClick(int x, int y);
- bool mouseRelease(int x, int y);
- bool mouseMove(int x, int y);
+ void setCommandsCallback(void (*callback)(int, Common::String &, void *), void *data) { _ccallback = callback; _cdata = data; }
+
+ void addStaticMenus(const MenuData *data);
+ void calcDimensions();
+
+ int addMenuItem(const char *name);
+ void addMenuSubItem(int id, const char *text, int action, int style = 0, char shortcut = 0, bool enabled = true);
+ void createSubMenuFromString(int id, const char *string);
+ void clearSubMenu(int id);
+
+ bool draw(Graphics::ManagedSurface *g, bool forceRedraw = false);
+ bool processEvent(Common::Event &event);
- void regenCommandsMenu();
- void regenWeaponsMenu();
- void processMenuShortCut(byte flags, uint16 ascii);
void enableCommand(int menunum, int action, bool state);
void disableAllMenus();
- bool _menuActivated;
+ void setActive(bool active) { _menuActivated = active; }
+ bool hasAllFocus() { return _menuActivated; }
+
Common::Rect _bbox;
private:
- Gui *_gui;
- Graphics::Surface _screenCopy;
- Graphics::Surface _tempSurface;
+ Graphics::ManagedSurface _screen;
+ Graphics::ManagedSurface _tempSurface;
private:
const Graphics::Font *getMenuFont();
@@ -120,18 +135,25 @@ private:
int calculateMenuWidth(MenuItem *menu);
void calcMenuBounds(MenuItem *menu);
void renderSubmenu(MenuItem *menu);
- void createCommandsMenu(MenuItem *menu);
- void createWeaponsMenu(MenuItem *menu);
- void executeCommand(MenuSubItem *subitem);
+
+ bool keyEvent(Common::Event &event);
+ bool mouseClick(int x, int y);
+ bool mouseRelease(int x, int y);
+ bool mouseMove(int x, int y);
+
+ bool processMenuShortCut(byte flags, uint16 ascii);
Common::Array<MenuItem *> _items;
- MenuItem *_weapons;
- MenuItem *_commands;
const Graphics::Font *_font;
+ bool _menuActivated;
+
int _activeItem;
int _activeSubItem;
+
+ void (*_ccallback)(int action, Common::String &text, void *data);
+ void *_cdata;
};
} // End of namespace Wage
diff --git a/engines/wage/macwindow.cpp b/engines/wage/macwindow.cpp
new file mode 100644
index 0000000000..db8ef38c39
--- /dev/null
+++ b/engines/wage/macwindow.cpp
@@ -0,0 +1,376 @@
+/* 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.
+ *
+ * MIT License:
+ *
+ * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko
+ *
+ * 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.
+ *
+ */
+
+#include "graphics/font.h"
+#include "graphics/primitives.h"
+#include "common/events.h"
+
+#include "wage/macwindow.h"
+#include "wage/macwindowmanager.h"
+
+namespace Wage {
+
+BaseMacWindow::BaseMacWindow(int id, bool editable, MacWindowManager *wm) :
+ _id(id), _editable(editable), _wm(wm) {
+ _callback = 0;
+ _dataPtr = 0;
+
+ _contentIsDirty = true;
+
+ _type = kWindowUnknown;
+}
+
+MacWindow::MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm) :
+ BaseMacWindow(id, editable, wm), _scrollable(scrollable), _resizable(resizable) {
+ _active = false;
+ _borderIsDirty = true;
+
+ _highlightedPart = kBorderNone;
+
+ _scrollPos = _scrollSize = 0.0;
+
+ _beingDragged = false;
+ _beingResized = false;
+
+ _draggedX = _draggedY = 0;
+
+ _type = kWindowWindow;
+}
+
+MacWindow::~MacWindow() {
+}
+
+const Graphics::Font *MacWindow::getTitleFont() {
+ return _wm->getFont("Chicago-12", Graphics::FontManager::kBigGUIFont);
+}
+
+void MacWindow::setActive(bool active) {
+ if (active == _active)
+ return;
+
+ _active = active;
+ _borderIsDirty = true;
+}
+
+void MacWindow::resize(int w, int h) {
+ if (_surface.w == w && _surface.h == h)
+ return;
+
+ _surface.free();
+ _surface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+ _borderSurface.free();
+ _borderSurface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+ _composeSurface.free();
+ _composeSurface.create(w, h, Graphics::PixelFormat::createFormatCLUT8());
+
+ _dims.setWidth(w);
+ _dims.setHeight(h);
+
+ updateInnerDims();
+
+ _contentIsDirty = true;
+ _borderIsDirty = true;
+}
+
+void MacWindow::move(int x, int y) {
+ if (_dims.left == x && _dims.top == y)
+ return;
+
+ _dims.moveTo(x, y);
+ updateInnerDims();
+
+ _contentIsDirty = true;
+}
+
+void MacWindow::setDimensions(const Common::Rect &r) {
+ resize(r.width(), r.height());
+ _dims.moveTo(r.left, r.top);
+ updateInnerDims();
+
+ _contentIsDirty = true;
+}
+
+bool MacWindow::draw(Graphics::ManagedSurface *g, bool forceRedraw) {
+ if (!_borderIsDirty && !_contentIsDirty && !forceRedraw)
+ return false;
+
+ if (_borderIsDirty || forceRedraw)
+ drawBorder();
+
+ _contentIsDirty = false;
+
+ // Compose
+ _composeSurface.blitFrom(_surface, Common::Rect(0, 0, _surface.w - 2, _surface.h - 2), Common::Point(2, 2));
+ _composeSurface.transBlitFrom(_borderSurface, kColorGreen);
+
+ g->transBlitFrom(_composeSurface, _composeSurface.getBounds(), Common::Point(_dims.left - 2, _dims.top - 2), kColorGreen2);
+
+ return true;
+}
+
+#define ARROW_W 12
+#define ARROW_H 6
+const int arrowPixels[ARROW_H][ARROW_W] = {
+ {0,0,0,0,0,1,1,0,0,0,0,0},
+ {0,0,0,0,1,1,1,1,0,0,0,0},
+ {0,0,0,1,1,1,1,1,1,0,0,0},
+ {0,0,1,1,1,1,1,1,1,1,0,0},
+ {0,1,1,1,1,1,1,1,1,1,1,0},
+ {1,1,1,1,1,1,1,1,1,1,1,1}};
+
+static void drawPixelInverted(int x, int y, int color, void *data) {
+ Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
+
+ if (x >= 0 && x < surface->w && y >= 0 && y < surface->h) {
+ byte *p = (byte *)surface->getBasePtr(x, y);
+
+ *p = *p == kColorWhite ? kColorBlack : kColorWhite;
+ }
+}
+
+void MacWindow::updateInnerDims() {
+ _innerDims = _dims;
+ _innerDims.grow(-kBorderWidth);
+}
+
+void MacWindow::drawBorder() {
+ _borderIsDirty = false;
+
+ bool active = _active, scrollable = _scrollable, closeable = _active, drawTitle = !_title.empty();
+ const int size = kBorderWidth;
+ int x = 0;
+ int y = 0;
+ int width = _borderSurface.w;
+ int height = _borderSurface.h;
+ Graphics::ManagedSurface *g = &_borderSurface;
+
+ // We draw rect with outer kColorGreen2 and inner kColorGreen, so on 2 passes we cut out
+ // scene by external shape of the border
+ int sz = kBorderWidth / 2;
+ g->clear(kColorGreen2);
+ g->fillRect(Common::Rect(sz, sz, width - sz, height - sz), kColorGreen);
+
+ drawBox(g, x, y, size, size);
+ drawBox(g, x + width - size - 1, y, size, size);
+ drawBox(g, x + width - size - 1, y + height - size - 1, size, size);
+ drawBox(g, x, y + height - size - 1, size, size);
+ drawBox(g, x + size, y + 2, width - 2 * size - 1, size - 4);
+ drawBox(g, x + size, y + height - size + 1, width - 2 * size - 1, size - 4);
+ drawBox(g, x + 2, y + size, size - 4, height - 2 * size - 1);
+ drawBox(g, x + width - size + 1, y + size, size - 4, height - 2 * size - 1);
+
+ if (active) {
+ fillRect(g, x + size, y + 5, width - 2 * size - 1, 8, kColorBlack);
+ fillRect(g, x + size, y + height - 13, width - 2 * size - 1, 8, kColorBlack);
+ fillRect(g, x + 5, y + size, 8, height - 2 * size - 1, kColorBlack);
+ if (!scrollable) {
+ fillRect(g, x + width - 13, y + size, 8, height - 2 * size - 1, kColorBlack);
+ } else {
+ int x1 = x + width - 15;
+ int y1 = y + size + 1;
+
+ for (int yy = 0; yy < ARROW_H; yy++) {
+ for (int xx = 0; xx < ARROW_W; xx++)
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[yy][xx] != 0 ? kColorBlack : kColorWhite));
+ }
+
+ fillRect(g, x + width - 13, y + size + ARROW_H, 8, height - 2 * size - 1 - ARROW_H * 2, kColorBlack);
+
+ y1 += height - 2 * size - ARROW_H - 2;
+ for (int yy = 0; yy < ARROW_H; yy++) {
+ for (int xx = 0; xx < ARROW_W; xx++)
+ g->hLine(x1 + xx, y1 + yy, x1 + xx, (arrowPixels[ARROW_H - yy - 1][xx] != 0 ? kColorBlack : kColorWhite));
+ }
+
+ if (_highlightedPart == kBorderScrollUp || _highlightedPart == kBorderScrollDown) {
+ int rx1 = x + width - kBorderWidth + 2;
+ int ry1 = y + size + _dims.height() * _scrollPos;
+ int rx2 = rx1 + size - 4;
+ int ry2 = ry1 + _dims.height() * _scrollSize;
+ Common::Rect rr(rx1, ry1, rx2, ry2);
+
+ Graphics::drawFilledRect(rr, kColorBlack, drawPixelInverted, g);
+ }
+ }
+ if (closeable) {
+ if (_highlightedPart == kBorderCloseButton) {
+ fillRect(g, x + 6, y + 6, 6, 6, kColorBlack);
+ } else {
+ drawBox(g, x + 5, y + 5, 7, 7);
+ }
+ }
+ }
+
+ if (drawTitle) {
+ const Graphics::Font *font = getTitleFont();
+ int yOff = _wm->hasBuiltInFonts() ? 3 : 1;
+
+ int w = font->getStringWidth(_title) + 10;
+ int maxWidth = width - size * 2 - 7;
+ if (w > maxWidth)
+ w = maxWidth;
+ drawBox(g, x + (width - w) / 2, y, w, size);
+ font->drawString(g, _title, x + (width - w) / 2 + 5, y + yOff, w, kColorBlack);
+ }
+}
+
+void MacWindow::setHighlight(WindowClick highlightedPart) {
+ if (_highlightedPart == highlightedPart)
+ return;
+
+ _highlightedPart = highlightedPart;
+ _borderIsDirty = true;
+}
+
+void MacWindow::setScroll(float scrollPos, float scrollSize) {
+ if (_scrollPos == scrollPos && _scrollSize == scrollSize)
+ return;
+
+ _scrollPos = scrollPos;
+ _scrollSize = scrollSize;
+ _borderIsDirty = true;
+}
+
+
+void MacWindow::drawBox(Graphics::ManagedSurface *g, int x, int y, int w, int h) {
+ Common::Rect r(x, y, x + w + 1, y + h + 1);
+
+ g->fillRect(r, kColorWhite);
+ g->frameRect(r, kColorBlack);
+}
+
+void MacWindow::fillRect(Graphics::ManagedSurface *g, int x, int y, int w, int h, int color) {
+ Common::Rect r(x, y, x + w, y + h);
+
+ g->fillRect(r, color);
+}
+
+WindowClick MacWindow::isInBorder(int x, int y) {
+ if (_innerDims.contains(x, y))
+ return kBorderInner;
+
+ if (x >= _innerDims.left - kBorderWidth && x < _innerDims.left && y >= _innerDims.top - kBorderWidth && y < _innerDims.top)
+ return kBorderCloseButton;
+
+ if (_resizable)
+ if (x >= _innerDims.right && x < _innerDims.right + kBorderWidth && y >= _innerDims.bottom && y < _innerDims.bottom + kBorderWidth)
+ return kBorderResizeButton;
+
+ if (_scrollable && x >= _innerDims.right && x < _innerDims.right + kBorderWidth) {
+ if (y < _innerDims.top - kBorderWidth)
+ return kBorderBorder;
+
+ if (y >= _innerDims.bottom + kBorderWidth)
+ return kBorderBorder;
+
+ if (y >= _innerDims.top + _innerDims.height() / 2)
+ return kBorderScrollDown;
+
+ return kBorderScrollUp;
+ }
+
+ return kBorderBorder;
+}
+
+bool MacWindow::processEvent(Common::Event &event) {
+ WindowClick click = isInBorder(event.mouse.x, event.mouse.y);
+
+ switch (event.type) {
+ case Common::EVENT_MOUSEMOVE:
+ if (_beingDragged) {
+ _dims.translate(event.mouse.x - _draggedX, event.mouse.y - _draggedY);
+ updateInnerDims();
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+
+ _wm->setFullRefresh(true);
+ }
+
+ if (_beingResized) {
+ resize(MAX(kBorderWidth * 4, _dims.width() + event.mouse.x - _draggedX),
+ MAX(kBorderWidth * 4, _dims.height() + event.mouse.y - _draggedY));
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+
+ _wm->setFullRefresh(true);
+ (*_callback)(click, event, _dataPtr);
+ }
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ setHighlight(click);
+
+ if (click == kBorderBorder) {
+ _beingDragged = true;
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+ }
+
+ if (click == kBorderResizeButton) {
+ _beingResized = true;
+
+ _draggedX = event.mouse.x;
+ _draggedY = event.mouse.y;
+ }
+
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _beingDragged = false;
+ _beingResized = false;
+
+ setHighlight(kBorderNone);
+ break;
+ default:
+ return false;
+ }
+
+ return (*_callback)(click, event, _dataPtr);
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/macwindow.h b/engines/wage/macwindow.h
new file mode 100644
index 0000000000..4c6e9efeff
--- /dev/null
+++ b/engines/wage/macwindow.h
@@ -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.
+ *
+ * MIT License:
+ *
+ * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko
+ *
+ * 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.
+ *
+ */
+
+#ifndef WAGE_MACWINDOW_H
+#define WAGE_MACWINDOW_H
+
+#include "graphics/managed_surface.h"
+
+namespace Wage {
+
+class MacWindowManager;
+
+enum WindowType {
+ kWindowUnknown,
+ kWindowWindow,
+ kWindowMenu
+};
+
+enum {
+ kBorderWidth = 17
+};
+
+enum WindowClick {
+ kBorderNone = 0,
+ kBorderScrollUp,
+ kBorderScrollDown,
+ kBorderCloseButton,
+ kBorderInner,
+ kBorderBorder,
+ kBorderResizeButton
+};
+
+class BaseMacWindow {
+public:
+ BaseMacWindow(int id, bool editable, MacWindowManager *wm);
+ virtual ~BaseMacWindow() {}
+
+ const Common::Rect &getDimensions() { return _dims; }
+ int getId() { return _id; }
+ WindowType getType() { return _type; }
+ bool isEditable() { return _editable; }
+ Graphics::ManagedSurface *getSurface() { return &_surface; }
+ virtual void setActive(bool active) = 0;
+ void setDirty(bool dirty) { _contentIsDirty = dirty; }
+
+ virtual bool draw(Graphics::ManagedSurface *g, bool forceRedraw = false) = 0;
+ virtual bool processEvent(Common::Event &event) = 0;
+
+ virtual bool hasAllFocus() = 0;
+
+ void setCallback(bool (*callback)(WindowClick, Common::Event &, void *), void *data) { _callback = callback; _dataPtr = data; }
+
+protected:
+ int _id;
+ WindowType _type;
+
+ bool _editable;
+
+ Graphics::ManagedSurface _surface;
+ bool _contentIsDirty;
+
+ Common::Rect _dims;
+
+ bool (*_callback)(WindowClick, Common::Event &, void *);
+ void *_dataPtr;
+
+ MacWindowManager *_wm;
+};
+
+class MacWindow : public BaseMacWindow {
+public:
+ MacWindow(int id, bool scrollable, bool resizable, bool editable, MacWindowManager *wm);
+ virtual ~MacWindow();
+ void move(int x, int y);
+ void resize(int w, int h);
+ void setDimensions(const Common::Rect &r);
+ const Common::Rect &getInnerDimensions() { return _innerDims; }
+
+ bool draw(Graphics::ManagedSurface *g, bool forceRedraw = false);
+
+ void setActive(bool active);
+ void setTitle(Common::String &title) { _title = title; }
+ void setHighlight(WindowClick highlightedPart);
+ void setScroll(float scrollPos, float scrollSize);
+ bool processEvent(Common::Event &event);
+ bool hasAllFocus() { return _beingDragged || _beingResized; }
+
+private:
+ void drawBorder();
+ void drawBox(Graphics::ManagedSurface *g, int x, int y, int w, int h);
+ void fillRect(Graphics::ManagedSurface *g, int x, int y, int w, int h, int color);
+ const Graphics::Font *getTitleFont();
+ void updateInnerDims();
+ WindowClick isInBorder(int x, int y);
+
+private:
+ Graphics::ManagedSurface _borderSurface;
+ Graphics::ManagedSurface _composeSurface;
+ bool _scrollable;
+ bool _resizable;
+ bool _active;
+ bool _borderIsDirty;
+
+ bool _beingDragged, _beingResized;
+ int _draggedX, _draggedY;
+
+ WindowClick _highlightedPart;
+ float _scrollPos, _scrollSize;
+
+ Common::Rect _innerDims;
+
+ Common::String _title;
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/macwindowmanager.cpp b/engines/wage/macwindowmanager.cpp
new file mode 100644
index 0000000000..6ca2efd7c9
--- /dev/null
+++ b/engines/wage/macwindowmanager.cpp
@@ -0,0 +1,379 @@
+/* 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.
+ *
+ * MIT License:
+ *
+ * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko
+ *
+ * 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.
+ *
+ */
+
+#include "common/array.h"
+#include "common/events.h"
+#include "common/list.h"
+#include "common/unzip.h"
+#include "common/system.h"
+#include "common/stream.h"
+
+#include "graphics/cursorman.h"
+#include "graphics/fonts/bdf.h"
+#include "graphics/managed_surface.h"
+#include "graphics/palette.h"
+#include "graphics/primitives.h"
+
+#include "wage/macwindowmanager.h"
+#include "wage/macwindow.h"
+#include "wage/macmenu.h"
+
+namespace Wage {
+
+static const byte palette[] = {
+ 0, 0, 0, // Black
+ 0x80, 0x80, 0x80, // Gray
+ 0xff, 0xff, 0xff, // White
+ 0x00, 0xff, 0x00, // Green
+ 0x00, 0xcf, 0x00 // Green2
+};
+
+static byte fillPatterns[][8] = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // kPatternSolid
+ { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, // kPatternStripes
+ { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }, // kPatternCheckers
+ { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa } // kPatternCheckers2
+};
+
+static const byte macCursorArrow[] = {
+ 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 2, 3, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 2, 3, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 2, 3, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 2, 3, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 2, 3, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3,
+ 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
+ 2, 0, 0, 2, 0, 0, 2, 3, 3, 3, 3,
+ 2, 0, 2, 3, 2, 0, 0, 2, 3, 3, 3,
+ 2, 2, 3, 3, 2, 0, 0, 2, 3, 3, 3,
+ 2, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
+ 3, 3, 3, 3, 3, 2, 0, 0, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3
+};
+
+static const byte macCursorBeam[] = {
+ 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+ 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3,
+ 0, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3,
+};
+
+MacWindowManager::MacWindowManager() {
+ _screen = 0;
+ _lastId = 0;
+ _activeWindow = -1;
+
+ _menu = 0;
+
+ _fullRefresh = true;
+
+ _builtInFonts = true;
+
+ for (int i = 0; i < ARRAYSIZE(fillPatterns); i++)
+ _patterns.push_back(fillPatterns[i]);
+
+ loadFonts();
+
+ g_system->getPaletteManager()->setPalette(palette, 0, ARRAYSIZE(palette) / 3);
+
+ CursorMan.replaceCursorPalette(palette, 0, ARRAYSIZE(palette) / 3);
+ CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
+ _cursorIsArrow = true;
+ CursorMan.showMouse(true);
+}
+
+MacWindowManager::~MacWindowManager() {
+ for (int i = 0; i < _lastId; i++)
+ delete _windows[i];
+}
+
+MacWindow *MacWindowManager::addWindow(bool scrollable, bool resizable, bool editable) {
+ MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this);
+
+ _windows.push_back(w);
+ _windowStack.push_back(w);
+
+ setActive(_lastId);
+
+ _lastId++;
+
+ return w;
+}
+
+Menu *MacWindowManager::addMenu() {
+ _menu = new Menu(_lastId, _screen->getBounds(), this);
+
+ _windows.push_back(_menu);
+
+ _lastId++;
+
+ return _menu;
+}
+
+void MacWindowManager::setActive(int id) {
+ if (_activeWindow == id)
+ return;
+
+ if (_activeWindow != -1)
+ _windows[_activeWindow]->setActive(false);
+
+ _activeWindow = id;
+
+ _windows[id]->setActive(true);
+
+ _windowStack.remove(_windows[id]);
+ _windowStack.push_back(_windows[id]);
+
+ _fullRefresh = true;
+}
+
+struct PlotData {
+ Graphics::ManagedSurface *surface;
+ Patterns *patterns;
+ uint fillType;
+ int thickness;
+
+ PlotData(Graphics::ManagedSurface *s, Patterns *p, int f, int t) :
+ surface(s), patterns(p), fillType(f), thickness(t) {}
+};
+
+static void drawPixel(int x, int y, int color, void *data) {
+ PlotData *p = (PlotData *)data;
+
+ if (p->fillType > p->patterns->size())
+ return;
+
+ byte *pat = p->patterns->operator[](p->fillType - 1);
+
+ if (p->thickness == 1) {
+ if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
+ uint xu = (uint)x; // for letting compiler optimize it
+ uint yu = (uint)y;
+
+ *((byte *)p->surface->getBasePtr(xu, yu)) =
+ (pat[yu % 8] & (1 << (7 - xu % 8))) ?
+ color : kColorWhite;
+ }
+ } else {
+ int x1 = x;
+ int x2 = x1 + p->thickness;
+ int y1 = y;
+ int y2 = y1 + p->thickness;
+
+ for (y = y1; y < y2; y++)
+ for (x = x1; x < x2; x++)
+ if (x >= 0 && x < p->surface->w && y >= 0 && y < p->surface->h) {
+ uint xu = (uint)x; // for letting compiler optimize it
+ uint yu = (uint)y;
+ *((byte *)p->surface->getBasePtr(xu, yu)) =
+ (pat[yu % 8] & (1 << (7 - xu % 8))) ?
+ color : kColorWhite;
+ }
+ }
+}
+
+void MacWindowManager::drawDesktop() {
+ Common::Rect r(_screen->getBounds());
+
+ PlotData pd(_screen, &_patterns, kPatternCheckers, 1);
+
+ Graphics::drawRoundRect(r, kDesktopArc, kColorBlack, true, drawPixel, &pd);
+
+ g_system->copyRectToScreen(_screen->getPixels(), _screen->pitch, 0, 0, _screen->w, _screen->h);
+}
+
+void MacWindowManager::draw() {
+ assert(_screen);
+
+ if (_fullRefresh)
+ drawDesktop();
+
+ for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++) {
+ BaseMacWindow *w = *it;
+ if (w->draw(_screen, _fullRefresh)) {
+ w->setDirty(false);
+
+ Common::Rect clip(w->getDimensions().left - 2, w->getDimensions().top - 2, w->getDimensions().right - 2, w->getDimensions().bottom - 2);
+ clip.clip(_screen->getBounds());
+
+ g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height());
+ }
+ }
+
+ // Menu is drawn on top of everything and always
+ if (_menu)
+ _menu->draw(_screen, _fullRefresh);
+
+ _fullRefresh = false;
+}
+
+bool MacWindowManager::processEvent(Common::Event &event) {
+ // Menu gets events first fir shortcuts and menu bar
+ if (_menu && _menu->processEvent(event))
+ return true;
+
+ if (event.type != Common::EVENT_MOUSEMOVE && event.type != Common::EVENT_LBUTTONDOWN &&
+ event.type != Common::EVENT_LBUTTONUP)
+ return false;
+
+ if (_windows[_activeWindow]->isEditable() && _windows[_activeWindow]->getType() == kWindowWindow &&
+ ((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y)) {
+ if (_cursorIsArrow) {
+ CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3);
+ _cursorIsArrow = false;
+ }
+ } else {
+ if (_cursorIsArrow == false) {
+ CursorMan.replaceCursor(macCursorArrow, 11, 16, 1, 1, 3);
+ _cursorIsArrow = true;
+ }
+ }
+
+ for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.end(); it != _windowStack.begin();) {
+ it--;
+ BaseMacWindow *w = *it;
+
+ if (w->hasAllFocus() || w->getDimensions().contains(event.mouse.x, event.mouse.y)) {
+ if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP)
+ setActive(w->getId());
+
+ return w->processEvent(event);
+ }
+ }
+
+ return false;
+}
+
+//////////////////////
+// Font stuff
+//////////////////////
+void MacWindowManager::loadFonts() {
+ Common::Archive *dat;
+
+ dat = Common::makeZipArchive("classicmacfonts.dat");
+
+ if (!dat) {
+ warning("Could not find classicmacfonts.dat. Falling back to built-in fonts");
+ _builtInFonts = true;
+
+ return;
+ }
+
+ Common::ArchiveMemberList list;
+ dat->listMembers(list);
+
+ for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
+ Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
+
+ Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream);
+
+ delete stream;
+
+ Common::String fontName = (*it)->getName();
+
+ // Trim the .bdf extension
+ for (int i = fontName.size() - 1; i >= 0; --i) {
+ if (fontName[i] == '.') {
+ while ((uint)i < fontName.size()) {
+ fontName.deleteLastChar();
+ }
+ break;
+ }
+ }
+
+ FontMan.assignFontToName(fontName, font);
+
+ debug(2, " %s", fontName.c_str());
+ }
+
+ _builtInFonts = false;
+
+ delete dat;
+}
+
+const Graphics::Font *MacWindowManager::getFont(const char *name, Graphics::FontManager::FontUsage fallback) {
+ const Graphics::Font *font = 0;
+
+ if (!_builtInFonts) {
+ font = FontMan.getFontByName(name);
+
+ if (!font)
+ warning("Cannot load font %s", name);
+ }
+
+ if (_builtInFonts || !font)
+ font = FontMan.getFontByUsage(fallback);
+
+ return font;
+}
+
+/////////////////
+// Cursor stuff
+/////////////////
+void MacWindowManager::pushArrowCursor() {
+ CursorMan.pushCursor(macCursorArrow, 11, 16, 1, 1, 3);
+}
+
+void MacWindowManager::popCursor() {
+ CursorMan.popCursor();
+}
+
+} // End of namespace Wage
diff --git a/engines/wage/macwindowmanager.h b/engines/wage/macwindowmanager.h
new file mode 100644
index 0000000000..13f85cddd4
--- /dev/null
+++ b/engines/wage/macwindowmanager.h
@@ -0,0 +1,141 @@
+/* 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.
+ *
+ * MIT License:
+ *
+ * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko
+ *
+ * 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.
+ *
+ */
+
+#ifndef WAGE_MACWINDOWMANAGER_H
+#define WAGE_MACWINDOWMANAGER_H
+
+#include "common/array.h"
+#include "common/list.h"
+#include "common/events.h"
+#include "common/archive.h"
+
+#include "graphics/fontman.h"
+
+namespace Graphics {
+class ManagedSurface;
+}
+
+namespace Wage {
+
+enum {
+ kDesktopArc = 7
+};
+
+enum {
+ kColorBlack = 0,
+ kColorGray = 1,
+ kColorWhite = 2,
+ kColorGreen = 3,
+ kColorGreen2 = 4
+};
+
+enum {
+ kPatternSolid = 1,
+ kPatternStripes = 2,
+ kPatternCheckers = 3,
+ kPatternCheckers2 = 4
+};
+
+class BaseMacWindow;
+class MacWindow;
+class Menu;
+
+typedef Common::Array<byte *> Patterns;
+
+class MacWindowManager {
+public:
+ MacWindowManager();
+ ~MacWindowManager();
+
+ void setScreen(Graphics::ManagedSurface *screen) { _screen = screen; }
+ bool hasBuiltInFonts() { return _builtInFonts; }
+ const Graphics::Font *getFont(const char *name, Graphics::FontManager::FontUsage fallback);
+
+ MacWindow *addWindow(bool scrollable, bool resizable, bool editable);
+ Menu *addMenu();
+ void setActive(int id);
+
+ void setFullRefresh(bool redraw) { _fullRefresh = true; }
+
+ void draw();
+
+ bool processEvent(Common::Event &event);
+
+ BaseMacWindow *getWindow(int id) { return _windows[id]; }
+
+ Patterns &getPatterns() { return _patterns; }
+ void drawFilledRoundRect(Graphics::ManagedSurface *surface, Common::Rect &rect, int arc, int color);
+
+ void pushArrowCursor();
+ void popCursor();
+
+private:
+ void drawDesktop();
+ void loadFonts();
+
+private:
+ Graphics::ManagedSurface *_screen;
+
+ Common::List<BaseMacWindow *> _windowStack;
+ Common::Array<BaseMacWindow *> _windows;
+
+ int _lastId;
+ int _activeWindow;
+
+ bool _fullRefresh;
+
+ Patterns _patterns;
+
+ Menu *_menu;
+
+ bool _builtInFonts;
+ bool _cursorIsArrow;
+};
+
+} // End of namespace Wage
+
+#endif
diff --git a/engines/wage/module.mk b/engines/wage/module.mk
index 548e440c28..e150d5f27e 100644
--- a/engines/wage/module.mk
+++ b/engines/wage/module.mk
@@ -2,13 +2,16 @@ MODULE := engines/wage
MODULE_OBJS := \
combat.o \
+ debugger.o \
design.o \
detection.o \
dialog.o \
entities.o \
gui.o \
gui-console.o \
- menu.o \
+ macmenu.o \
+ macwindow.o \
+ macwindowmanager.o \
randomhat.o \
script.o \
sound.o \
diff --git a/engines/wage/script.cpp b/engines/wage/script.cpp
index bd99fa1d86..61336dce88 100644
--- a/engines/wage/script.cpp
+++ b/engines/wage/script.cpp
@@ -1099,7 +1099,7 @@ struct Mapping {
{ "\?\?\?(0xf5)", OPCODE },
{ "\?\?\?(0xf6)", OPCODE },
{ "\?\?\?(0xf7)", OPCODE },
- { "\?\?\?(0xf8)", OPCODE }, // 0xa8
+ { "\?\?\?(0xf8)", OPCODE }, // 0xf8
{ "\?\?\?(0xf9)", OPCODE },
{ "\?\?\?(0xfa)", OPCODE },
{ "\?\?\?(0xfb)", OPCODE },
@@ -1124,7 +1124,7 @@ void Script::convertToText() {
if (c < 0x80) {
if (c < 0x20)
- error("Unknown code 0x%02x at %d", c, _data->pos());
+ error("convertToText: Unknown code 0x%02x at %d", c, _data->pos());
do {
scr->line += c;
diff --git a/engines/wage/script.h b/engines/wage/script.h
index 325733add7..de9476228c 100644
--- a/engines/wage/script.h
+++ b/engines/wage/script.h
@@ -150,8 +150,10 @@ private:
void assign(byte operandType, int uservar, uint16 value);
- Common::Array<ScriptText *> _scriptText;
void convertToText();
+
+public:
+ Common::Array<ScriptText *> _scriptText;
};
} // End of namespace Wage
diff --git a/engines/wage/util.cpp b/engines/wage/util.cpp
index 1b3dfc9452..8c8af6652e 100644
--- a/engines/wage/util.cpp
+++ b/engines/wage/util.cpp
@@ -81,6 +81,8 @@ Common::Rect *readRect(Common::SeekableReadStream *in) {
y2 = in->readUint16BE() + 4;
x2 = in->readUint16BE() + 4;
+ debug(9, "readRect: %d, %d, %d, %d", x1, y1, x2, y2);
+
return new Common::Rect(x1, y1, x2, y2);
}
@@ -120,4 +122,17 @@ const char *getGenderSpecificPronoun(int gender, bool capitalize) {
return capitalize ? "It" : "it";
}
+bool isStorageScene(const Common::String &name) {
+ if (name.equalsIgnoreCase(STORAGESCENE))
+ return true;
+
+ if (name.equalsIgnoreCase("STROAGE@")) // Jumble
+ return true;
+
+ if (name.equalsIgnoreCase("STORAGE@@")) // Jumble
+ return true;
+
+ return false;
+}
+
} // End of namespace Wage
diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp
index b708cff134..567e2768d8 100644
--- a/engines/wage/wage.cpp
+++ b/engines/wage/wage.cpp
@@ -86,6 +86,7 @@ WageEngine::WageEngine(OSystem *syst, const ADGameDescription *desc) : Engine(sy
_offer = NULL;
_resManager = NULL;
+ _debugger = NULL;
debug("WageEngine::WageEngine()");
}
@@ -102,12 +103,14 @@ WageEngine::~WageEngine() {
}
Common::Error WageEngine::run() {
+ debug("WageEngine::init");
+
initGraphics(512, 342, true);
// Create debugger console. It requires GFX to be initialized
_console = new Console(this);
- debug("WageEngine::init");
+ _debugger = new Debugger(this);
// Your main event loop should be (invoked from) here.
_resManager = new Common::MacResManager();
@@ -130,6 +133,8 @@ Common::Error WageEngine::run() {
_shouldQuit = false;
while (!_shouldQuit) {
+ _debugger->onFrame();
+
processEvents();
_gui->draw();
@@ -144,24 +149,14 @@ void WageEngine::processEvents() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
+ if (_gui->processEvent(event))
+ continue;
+
switch (event.type) {
case Common::EVENT_QUIT:
if (saveDialog())
_shouldQuit = true;
break;
- case Common::EVENT_MOUSEMOVE:
- _gui->mouseMove(event.mouse.x, event.mouse.y);
- break;
- case Common::EVENT_LBUTTONDOWN:
- _gui->mouseDown(event.mouse.x, event.mouse.y);
- break;
- case Common::EVENT_LBUTTONUP:
- {
- Designed *obj = _gui->mouseUp(event.mouse.x, event.mouse.y);
- if (obj != NULL)
- processTurn(NULL, obj);
- }
- break;
case Common::EVENT_KEYDOWN:
switch (event.kbd.keycode) {
case Common::KEYCODE_BACKSPACE:
@@ -180,10 +175,8 @@ void WageEngine::processEvents() {
break;
default:
- if (event.kbd.flags & (Common::KBD_ALT | Common::KBD_CTRL | Common::KBD_META)) {
- if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
- _gui->processMenuShortCut(event.kbd.flags, event.kbd.ascii);
- }
+ if (event.kbd.ascii == '~') {
+ _debugger->attach();
break;
}
@@ -227,7 +220,6 @@ void WageEngine::gameOver() {
_gui->disableAllMenus();
_gui->enableNewGameMenus();
- _gui->_menuDirty = true;
}
bool WageEngine::saveDialog() {
@@ -272,15 +264,16 @@ void WageEngine::performInitialSetup() {
debug(5, "Resetting Owners: %d", _world->_orderedObjs.size());
for (uint i = 0; i < _world->_orderedObjs.size(); i++) {
Obj *obj = _world->_orderedObjs[i];
- if (!obj->_sceneOrOwner.equalsIgnoreCase(STORAGESCENE)) {
+ if (!isStorageScene(obj->_sceneOrOwner)) {
Common::String location = obj->_sceneOrOwner;
location.toLowercase();
- if (_world->_scenes.contains(location)) {
- _world->move(obj, _world->_scenes[location]);
+ Scene *scene = getSceneByName(location);
+ if (scene != NULL) {
+ _world->move(obj, scene);
} else {
if (!_world->_chrs.contains(location)) {
// Note: PLAYER@ is not a valid target here.
- warning("Couldn't move %s to %s", obj->_name.c_str(), obj->_sceneOrOwner.c_str());
+ warning("Couldn't move %s to \"%s\"", obj->_name.c_str(), obj->_sceneOrOwner.c_str());
} else {
// TODO: Add check for max items.
_world->move(obj, _world->_chrs[location]);
@@ -292,7 +285,7 @@ void WageEngine::performInitialSetup() {
bool playerPlaced = false;
for (uint i = 0; i < _world->_orderedChrs.size(); i++) {
Chr *chr = _world->_orderedChrs[i];
- if (!chr->_initialScene.equalsIgnoreCase(STORAGESCENE)) {
+ if (!isStorageScene(chr->_initialScene)) {
Common::String key = chr->_initialScene;
key.toLowercase();
if (_world->_scenes.contains(key) && _world->_scenes[key] != NULL) {
@@ -319,13 +312,14 @@ void WageEngine::doClose() {
}
Scene *WageEngine::getSceneByName(Common::String &location) {
- Scene *scene;
if (location.equals("random@")) {
- scene = _world->getRandomScene();
+ return _world->getRandomScene();
} else {
- scene = _world->_scenes[location];
+ if (_world->_scenes.contains(location))
+ return _world->_scenes[location];
+ else
+ return NULL;
}
- return scene;
}
void WageEngine::onMove(Designed *what, Designed *from, Designed *to) {
@@ -377,6 +371,7 @@ void WageEngine::onMove(Designed *what, Designed *from, Designed *to) {
if (!_temporarilyHidden) {
if (to == currentScene || from == currentScene) {
redrawScene();
+ g_system->updateScreen();
g_system->delayMillis(100);
}
}
@@ -388,6 +383,7 @@ void WageEngine::redrawScene() {
if (currentScene != NULL) {
bool firstTime = (_lastScene != currentScene);
+ _gui->draw();
updateSoundTimerForScene(currentScene, firstTime);
}
}
diff --git a/engines/wage/wage.h b/engines/wage/wage.h
index 6905fdc530..eb50a2e3dd 100644
--- a/engines/wage/wage.h
+++ b/engines/wage/wage.h
@@ -50,12 +50,13 @@
#include "engines/engine.h"
#include "common/debug.h"
-#include "gui/debugger.h"
#include "common/endian.h"
#include "common/rect.h"
#include "common/macresman.h"
#include "common/random.h"
+#include "wage/debugger.h"
+
struct ADGameDescription;
namespace Wage {
@@ -74,6 +75,8 @@ typedef Common::Array<Chr *> ChrArray;
typedef Common::List<Obj *> ObjList;
typedef Common::List<Chr *> ChrList;
+#define STORAGESCENE "STORAGE@"
+
enum OperandType {
OBJ = 0,
CHR = 1,
@@ -100,21 +103,12 @@ enum {
// the current limitation is 32 debug levels (1 << 31 is the last one)
};
-enum {
- kColorBlack = 0,
- kColorGray = 1,
- kColorWhite = 2,
- kColorGreen = 3
-};
-
Common::String readPascalString(Common::SeekableReadStream *in);
Common::Rect *readRect(Common::SeekableReadStream *in);
const char *getIndefiniteArticle(const Common::String &word);
const char *prependGenderSpecificPronoun(int gender);
const char *getGenderSpecificPronoun(int gender, bool capitalize);
-
-
-typedef Common::Array<byte *> Patterns;
+bool isStorageScene(const Common::String &name);
class WageEngine : public Engine {
friend class Dialog;
@@ -181,6 +175,8 @@ public:
public:
Common::RandomSource *_rnd;
+ Debugger *_debugger;
+
Gui *_gui;
World *_world;
@@ -212,6 +208,8 @@ public:
void redrawScene();
void saveGame();
+ virtual GUI::Debugger *getDebugger() { return _debugger; }
+
private:
Console *_console;
diff --git a/engines/wage/world.cpp b/engines/wage/world.cpp
index 40b1555e35..0e40e114b4 100644
--- a/engines/wage/world.cpp
+++ b/engines/wage/world.cpp
@@ -73,6 +73,8 @@ World::World(WageEngine *engine) {
_weaponMenuDisabled = true;
_engine = engine;
+
+ _patterns = new Patterns;
}
World::~World() {
@@ -88,8 +90,10 @@ World::~World() {
for (uint i = 0; i < _orderedScenes.size(); i++)
delete _orderedScenes[i];
- for (uint i = 0; i < _patterns.size(); i++)
- free(_patterns[i]);
+ for (uint i = 0; i < _patterns->size(); i++)
+ free(_patterns->operator[](i));
+
+ delete _patterns;
delete _globalScript;
@@ -105,6 +109,20 @@ bool World::loadWorld(Common::MacResManager *resMan) {
Common::SeekableReadStream *res;
Common::MacResIDArray::const_iterator iter;
+ // Dumping interpreter code
+#if 1
+ res = resMan->getResource(MKTAG('C','O','D','E'), 1);
+ warning("code size: %d", res->size());
+ byte *buf = (byte *)malloc(res->size());
+ res->read(buf, res->size());
+ Common::DumpFile out;
+ out.open("code.bin");
+ out.write(buf, res->size());
+ out.close();
+ free(buf);
+ delete res;
+#endif
+
if ((resArray = resMan->getResIDArray(MKTAG('G','C','O','D'))).size() == 0)
return false;
@@ -249,7 +267,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
byte *pattern = (byte *)malloc(8);
res->read(pattern, 8);
- _patterns.push_back(pattern);
+ _patterns->push_back(pattern);
}
delete res;
@@ -262,7 +280,7 @@ bool World::loadWorld(Common::MacResManager *resMan) {
byte *pattern = (byte *)malloc(8);
res->read(pattern, 8);
- _patterns.push_back(pattern);
+ _patterns->push_back(pattern);
}
}
delete res;
@@ -399,7 +417,7 @@ Common::String *World::loadStringFromDITL(Common::MacResManager *resMan, int res
}
static bool invComparator(const Obj *l, const Obj *r) {
- return l->_index < r->_index;
+ return l->_index < r->_index;
}
void World::move(Obj *obj, Chr *chr) {
@@ -419,7 +437,7 @@ static bool objComparator(const Obj *o1, const Obj *o2) {
bool o1Immobile = (o1->_type == Obj::IMMOBILE_OBJECT);
bool o2Immobile = (o2->_type == Obj::IMMOBILE_OBJECT);
if (o1Immobile == o2Immobile) {
- return o1->_index - o2->_index;
+ return o1->_index < o2->_index;
}
return o1Immobile;
}
@@ -439,7 +457,7 @@ void World::move(Obj *obj, Scene *scene, bool skipSort) {
}
static bool chrComparator(const Chr *l, const Chr *r) {
- return l->_index < r->_index;
+ return l->_index < r->_index;
}
void World::move(Chr *chr, Scene *scene, bool skipSort) {
diff --git a/engines/wage/world.h b/engines/wage/world.h
index e9041139df..468bedbc59 100644
--- a/engines/wage/world.h
+++ b/engines/wage/world.h
@@ -48,9 +48,9 @@
#ifndef WAGE_WORLD_H
#define WAGE_WORLD_H
-namespace Wage {
+#include "wage/macwindowmanager.h"
-#define STORAGESCENE "STORAGE@"
+namespace Wage {
class Sound;
@@ -87,7 +87,7 @@ public:
ObjArray _orderedObjs;
ChrArray _orderedChrs;
Common::Array<Sound *> _orderedSounds;
- Patterns _patterns;
+ Patterns *_patterns;
Scene *_storageScene;
Chr *_player;
//List<MoveListener> moveListeners;
diff --git a/engines/wintermute/base/base_engine.cpp b/engines/wintermute/base/base_engine.cpp
index 2166a3e070..4ce334aceb 100644
--- a/engines/wintermute/base/base_engine.cpp
+++ b/engines/wintermute/base/base_engine.cpp
@@ -84,7 +84,7 @@ void BaseEngine::LOG(bool res, const char *fmt, ...) {
va_end(va);
if (instance()._gameRef) {
- instance()._gameRef->LOG("%s", buff);
+ instance()._gameRef->LOG(res, "%s", buff);
} else {
debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
}
diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h
index 0f4a6b0775..cbf5d92d00 100644
--- a/engines/wintermute/base/base_engine.h
+++ b/engines/wintermute/base/base_engine.h
@@ -74,7 +74,7 @@ public:
static const Timer *getTimer();
static const Timer *getLiveTimer();
static void LOG(bool res, const char *fmt, ...);
- const char *getGameTargetName() const { return _targetName.c_str(); }
+ Common::String getGameTargetName() const { return _targetName; }
Common::String getGameId() const { return _gameId; }
Common::Language getLanguage() const { return _language; }
WMETargetExecutable getTargetExecutable() const {
diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp
index bb5e0c4091..5a694e7ce2 100644
--- a/engines/wintermute/base/base_persistence_manager.cpp
+++ b/engines/wintermute/base/base_persistence_manager.cpp
@@ -56,7 +56,7 @@ namespace Wintermute {
#define SAVE_MAGIC_3 0x12564154
//////////////////////////////////////////////////////////////////////////
-BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool deleteSingleton) {
+BasePersistenceManager::BasePersistenceManager(const Common::String &savePrefix, bool deleteSingleton) {
_saving = false;
_offset = 0;
_saveStream = nullptr;
@@ -91,7 +91,7 @@ BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool dele
_thumbnailDataSize = 0;
_thumbnailData = nullptr;
- if (savePrefix) {
+ if (savePrefix != "") {
_savePrefix = savePrefix;
} else if (_gameRef) {
_savePrefix = _gameRef->getGameTargetName();
@@ -183,7 +183,7 @@ void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &des
}
}
- desc.setSaveDate(_savedTimestamp.tm_year, _savedTimestamp.tm_mon, _savedTimestamp.tm_mday);
+ desc.setSaveDate(_savedTimestamp.tm_year + 1900, _savedTimestamp.tm_mon + 1, _savedTimestamp.tm_mday);
desc.setSaveTime(_savedTimestamp.tm_hour, _savedTimestamp.tm_min);
desc.setPlayTime(0);
}
@@ -215,8 +215,8 @@ bool BasePersistenceManager::getSaveExists(int slot) {
}
//////////////////////////////////////////////////////////////////////////
-bool BasePersistenceManager::initSave(const char *desc) {
- if (!desc) {
+bool BasePersistenceManager::initSave(const Common::String &desc) {
+ if (desc == "") {
return STATUS_FAILED;
}
@@ -297,11 +297,11 @@ bool BasePersistenceManager::initSave(const char *desc) {
uint32 dataOffset = _offset +
sizeof(uint32) + // data offset
- sizeof(uint32) + strlen(desc) + 1 + // description
+ sizeof(uint32) + strlen(desc.c_str()) + 1 + // description
sizeof(uint32); // timestamp
putDWORD(dataOffset);
- putString(desc);
+ putString(desc.c_str());
g_system->getTimeAndDate(_savedTimestamp);
putTimeDate(_savedTimestamp);
diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h
index 373d1580de..760b45c907 100644
--- a/engines/wintermute/base/base_persistence_manager.h
+++ b/engines/wintermute/base/base_persistence_manager.h
@@ -63,7 +63,7 @@ public:
uint32 getMaxUsedSlot();
bool getSaveExists(int slot);
bool initLoad(const Common::String &filename);
- bool initSave(const char *desc);
+ bool initSave(const Common::String &desc);
bool getBytes(byte *buffer, uint32 size);
bool putBytes(byte *buffer, uint32 size);
uint32 _offset;
@@ -86,7 +86,7 @@ public:
bool transferCharPtr(const char *name, char **val);
bool transferString(const char *name, Common::String *val);
bool transferVector2(const char *name, Vector2 *val);
- BasePersistenceManager(const char *savePrefix = nullptr, bool deleteSingleton = false);
+ BasePersistenceManager(const Common::String &savePrefix = "", bool deleteSingleton = false);
virtual ~BasePersistenceManager();
bool checkVersion(byte verMajor, byte verMinor, byte verBuild);
diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp
index 82a9e24dfb..d0c51616f4 100644
--- a/engines/wintermute/base/file/base_disk_file.cpp
+++ b/engines/wintermute/base/file/base_disk_file.cpp
@@ -113,13 +113,28 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) {
Common::String fixedFilename = filename;
correctSlashes(fixedFilename);
- // Absolute path: TODO: Add specific fallbacks here.
+ // HACK: There are a few games around which mistakenly refer to absolute paths in the scripts.
+ // The original interpreter on Windows usually simply ignores them when it can't find them.
+ // We try to turn the known ones into relative paths.
if (fixedFilename.contains(':')) {
- if (fixedFilename.hasPrefix("c:/windows/fonts/")) { // East Side Story refers to "c:\windows\fonts\framd.ttf"
- fixedFilename = filename.c_str() + 14;
- } else if (fixedFilename.hasPrefix("c:/carol6/svn/data/")) { // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png"
- fixedFilename = fixedFilename.c_str() + 19;
- } else {
+ const char* const knownPrefixes[] = { // Known absolute paths
+ "c:/windows/fonts/", // East Side Story refers to "c:\windows\fonts\framd.ttf"
+ "c:/carol6/svn/data/", // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png"
+ "f:/dokument/spel 5/demo/data/" // Carol Reed 5 (non-demo) refers to "f:\dokument\spel 5\demo\data\scenes\credits\op_cred_00\op_cred_00.jpg"
+ };
+
+ bool matched = false;
+
+ for (uint i = 0; i < ARRAYSIZE(knownPrefixes); i++) {
+ if (fixedFilename.hasPrefix(knownPrefixes[i])) {
+ fixedFilename = fixedFilename.c_str() + strlen(knownPrefixes[i]);
+ matched = true;
+ }
+ }
+
+ if (!matched) {
+ // fixedFilename is unchanged and thus still broken, none of the above workarounds worked.
+ // We can only bail out
error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str());
}
}
diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp
index f1e0c3b1f9..74c0086817 100644
--- a/engines/wintermute/base/sound/base_sound_manager.cpp
+++ b/engines/wintermute/base/sound/base_sound_manager.cpp
@@ -100,15 +100,14 @@ BaseSoundBuffer *BaseSoundMgr::addSound(const Common::String &filename, Audio::M
BaseSoundBuffer *sound;
Common::String useFilename = filename;
+ useFilename.toLowercase();
// try to switch WAV to OGG file (if available)
- AnsiString ext = PathUtil::getExtension(filename);
- if (StringUtil::compareNoCase(ext, "wav")) {
- AnsiString path = PathUtil::getDirectoryName(filename);
- AnsiString name = PathUtil::getFileNameWithoutExtension(filename);
-
- AnsiString newFile = PathUtil::combine(path, name + "ogg");
- if (BaseFileManager::getEngineInstance()->hasFile(newFile)) {
- useFilename = newFile;
+ if (useFilename.hasSuffix(".wav")) {
+ Common::String oggFilename = useFilename;
+ oggFilename.erase(oggFilename.size() - 4);
+ oggFilename = oggFilename + ".ogg";
+ if (BaseFileManager::getEngineInstance()->hasFile(oggFilename)) {
+ useFilename = oggFilename;
}
}
diff --git a/engines/wintermute/configure.engine b/engines/wintermute/configure.engine
index bdaf49de3f..55385776de 100644
--- a/engines/wintermute/configure.engine
+++ b/engines/wintermute/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit"
+add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit highres"
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index aca682ae99..4e8eab505f 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -75,8 +75,8 @@ static const char *directoryGlobs[] = {
class WintermuteMetaEngine : public AdvancedMetaEngine {
public:
WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) {
- _singleid = "wintermute";
- _guioptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS);
+ _singleId = "wintermute";
+ _guiOptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS);
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
@@ -85,7 +85,7 @@ public:
}
virtual const char *getOriginalCopyright() const {
- return "Copyright (c) 2011 Jan Nedoma";
+ return "Copyright (C) 2011 Jan Nedoma";
}
virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
@@ -94,8 +94,8 @@ public:
s_fallbackDesc.language = Common::UNK_LANG;
s_fallbackDesc.flags = ADGF_UNSTABLE;
s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows
- s_fallbackDesc.gameid = "wintermute";
- s_fallbackDesc.guioptions = GUIO0();
+ s_fallbackDesc.gameId = "wintermute";
+ s_fallbackDesc.guiOptions = GUIO0();
if (allFiles.contains("data.dcp")) {
Common::String name, caption;
@@ -109,7 +109,7 @@ public:
// Prefix to avoid collisions with actually known games
name = "wmeunk-" + name;
Common::strlcpy(s_fallbackGameIdBuf, name.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
- s_fallbackDesc.gameid = s_fallbackGameIdBuf;
+ s_fallbackDesc.gameId = s_fallbackGameIdBuf;
if (caption != name) {
caption += " (unknown version) ";
char *offset = s_fallbackGameIdBuf + name.size() + 1;
diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h
index 25a01766e4..ca30204462 100644
--- a/engines/wintermute/detection_tables.h
+++ b/engines/wintermute/detection_tables.h
@@ -181,10 +181,13 @@ static const WMEGameDescription gameDescriptions[] = {
WME_ENTRY1s("data.dcp", "b3f8b09bb4b05ee3e9d14697525257f9", 59296246), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Carol Reed 4 - East Side Story
WME_WINENTRY("carolreed4", "",
- WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
+ WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
// Carol Reed 5 - The Colour of Murder
WME_WINENTRY("carolreed5", "",
WME_ENTRY1s("data.dcp", "3fcfca44209545d0e26774156427b494", 603660415), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
+ // Carol Reed 5 - The Colour of Murder (1.0 Demo)
+ WME_WINENTRY("carolreed5", "Demo",
+ WME_ENTRY1s("data.dcp", "27b3efc018ade5ee8f4adf08b4e3c0dd", 92019500), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION),
// Carol Reed 6 - Black Circle
WME_WINENTRY("carolreed6", "",
WME_ENTRY1s("data.dcp", "0e4c532beecf23d85012168753f41189", 456258147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION),
diff --git a/engines/wintermute/ui/ui_window.cpp b/engines/wintermute/ui/ui_window.cpp
index 9f3cdeaaa3..34341d1db2 100644
--- a/engines/wintermute/ui/ui_window.cpp
+++ b/engines/wintermute/ui/ui_window.cpp
@@ -139,13 +139,12 @@ bool UIWindow::display(int offsetX, int offsetY) {
_shieldButton->setListener(this, _shieldButton, 0);
_shieldButton->_parent = this;
}
- if (_shieldButton) {
- _shieldButton->_posX = _shieldButton->_posY = 0;
- _shieldButton->setWidth(_gameRef->_renderer->getWidth());
- _shieldButton->setHeight(_gameRef->_renderer->getHeight());
- _shieldButton->display();
- }
+ _shieldButton->_posX = _shieldButton->_posY = 0;
+ _shieldButton->setWidth(_gameRef->_renderer->getWidth());
+ _shieldButton->setHeight(_gameRef->_renderer->getHeight());
+
+ _shieldButton->display();
}
if (!_visible) {
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index 6f0e3edc13..05dfb961cb 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -137,7 +137,7 @@ Common::Error WintermuteEngine::run() {
}
int WintermuteEngine::init() {
- BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameid, _gameDescription->adDesc.language, _gameDescription->targetExecutable);
+ BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameId, _gameDescription->adDesc.language, _gameDescription->targetExecutable);
_game = new AdGame(_targetName);
if (!_game) {
return 1;
diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h
index 5071a84d32..a8f9a18530 100644
--- a/engines/wintermute/wintermute.h
+++ b/engines/wintermute/wintermute.h
@@ -20,8 +20,8 @@
*
*/
-#ifndef WINTERMUTE_H
-#define WINTERMUTE_H
+#ifndef WINTERMUTE_WINTERMUTE_H
+#define WINTERMUTE_WINTERMUTE_H
#include "engines/engine.h"
#include "engines/advancedDetector.h"
diff --git a/engines/zvision/configure.engine b/engines/zvision/configure.engine
index 226870c3fd..8681522a35 100644
--- a/engines/zvision/configure.engine
+++ b/engines/zvision/configure.engine
@@ -1,3 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
-add_engine zvision "Z-Vision" yes "" "" "freetype2 16bit"
+add_engine zvision "Z-Vision" yes "" "" "freetype2 16bit highres"
diff --git a/engines/zvision/core/events.cpp b/engines/zvision/core/events.cpp
index cc1c00b6d0..767101b952 100644
--- a/engines/zvision/core/events.cpp
+++ b/engines/zvision/core/events.cpp
@@ -35,6 +35,7 @@
#include "common/events.h"
#include "common/system.h"
#include "common/rational.h"
+#include "audio/mixer.h"
#include "engines/util.h"
diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp
index 8b47590861..cc967070d9 100644
--- a/engines/zvision/detection.cpp
+++ b/engines/zvision/detection.cpp
@@ -61,7 +61,7 @@ public:
ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), ZVision::zVisionGames, ZVision::optionsList) {
_maxScanDepth = 2;
_directoryGlobs = ZVision::directoryGlobs;
- _singleid = "zvision";
+ _singleId = "zvision";
}
virtual const char *getName() const {
diff --git a/engines/zvision/scripting/actions.h b/engines/zvision/scripting/actions.h
index bde1baa291..98d216a6d5 100644
--- a/engines/zvision/scripting/actions.h
+++ b/engines/zvision/scripting/actions.h
@@ -26,8 +26,6 @@
#include "common/str.h"
#include "common/rect.h"
-#include "audio/mixer.h"
-
namespace ZVision {
// Forward declaration of ZVision. This file is included before ZVision is declared
diff --git a/engines/zvision/sound/midi.cpp b/engines/zvision/sound/midi.cpp
index 3dd66ff2d4..9366f9e1e4 100644
--- a/engines/zvision/sound/midi.cpp
+++ b/engines/zvision/sound/midi.cpp
@@ -22,6 +22,7 @@
#include "common/scummsys.h"
#include "common/textconsole.h"
+#include "audio/mididrv.h"
#include "zvision/sound/midi.h"
diff --git a/engines/zvision/sound/midi.h b/engines/zvision/sound/midi.h
index a3bac19636..020c65c9f7 100644
--- a/engines/zvision/sound/midi.h
+++ b/engines/zvision/sound/midi.h
@@ -23,7 +23,7 @@
#ifndef ZVISION_MIDI_H
#define ZVISION_MIDI_H
-#include "audio/mididrv.h"
+class MidiDriver;
namespace ZVision {
diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp
index b0d69c5f94..05db284f62 100644
--- a/engines/zvision/zvision.cpp
+++ b/engines/zvision/zvision.cpp
@@ -34,13 +34,13 @@
#include "zvision/text/text.h"
#include "zvision/text/truetype_font.h"
#include "zvision/sound/midi.h"
-#include "zvision/file/zfs_archive.h"
#include "common/config-manager.h"
#include "common/str.h"
#include "common/debug.h"
#include "common/debug-channels.h"
#include "common/textconsole.h"
+#include "common/timer.h"
#include "common/error.h"
#include "common/system.h"
#include "common/file.h"
diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp
index f426dd8c41..73dc6309b2 100644
--- a/graphics/VectorRenderer.cpp
+++ b/graphics/VectorRenderer.cpp
@@ -55,7 +55,34 @@ void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step, ui
_dynamicData = extra;
- (this->*(step.drawingCall))(area, step);
+ Common::Rect noClip = Common::Rect(0, 0, 0, 0);
+ (this->*(step.drawingCall))(area, step, noClip);
+}
+
+void VectorRenderer::drawStepClip(const Common::Rect &area, const Common::Rect &clip, const DrawStep &step, uint32 extra) {
+
+ if (step.bgColor.set)
+ setBgColor(step.bgColor.r, step.bgColor.g, step.bgColor.b);
+
+ if (step.fgColor.set)
+ setFgColor(step.fgColor.r, step.fgColor.g, step.fgColor.b);
+
+ if (step.bevelColor.set)
+ setBevelColor(step.bevelColor.r, step.bevelColor.g, step.bevelColor.b);
+
+ if (step.gradColor1.set && step.gradColor2.set)
+ setGradientColors(step.gradColor1.r, step.gradColor1.g, step.gradColor1.b,
+ step.gradColor2.r, step.gradColor2.g, step.gradColor2.b);
+
+ setShadowOffset(_disableShadows ? 0 : step.shadow);
+ setBevel(step.bevel);
+ setGradientFactor(step.factor);
+ setStrokeWidth(step.stroke);
+ setFillMode((FillMode)step.fillMode);
+
+ _dynamicData = extra;
+
+ (this->*(step.drawingCall))(area, step, clip);
}
int VectorRenderer::stepGetRadius(const DrawStep &step, const Common::Rect &area) {
diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h
index 6b657f758d..0352808706 100644
--- a/graphics/VectorRenderer.h
+++ b/graphics/VectorRenderer.h
@@ -38,7 +38,7 @@ class VectorRenderer;
struct DrawStep;
-typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &);
+typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &, const Common::Rect &);
struct DrawStep {
@@ -142,6 +142,7 @@ public:
* @param y2 Vertical (Y) coordinate for the line end
*/
virtual void drawLine(int x1, int y1, int x2, int y2) = 0;
+ virtual void drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) = 0;
/**
* Draws a circle centered at (x,y) with radius r.
@@ -151,6 +152,7 @@ public:
* @param r Radius of the circle.
*/
virtual void drawCircle(int x, int y, int r) = 0;
+ virtual void drawCircleClip(int x, int y, int r, Common::Rect clipping) = 0;
/**
* Draws a square starting at (x,y) with the given width and height.
@@ -161,6 +163,7 @@ public:
* @param h Height of the square
*/
virtual void drawSquare(int x, int y, int w, int h) = 0;
+ virtual void drawSquareClip(int x, int y, int w, int h, Common::Rect clipping) = 0;
/**
* Draws a rounded square starting at (x,y) with the given width and height.
@@ -173,6 +176,7 @@ public:
* @param r Radius of the corners.
*/
virtual void drawRoundedSquare(int x, int y, int r, int w, int h) = 0;
+ virtual void drawRoundedSquareClip(int x, int y, int r, int w, int h, Common::Rect clipping) = 0;
/**
* Draws a triangle starting at (x,y) with the given base and height.
@@ -186,6 +190,7 @@ public:
* @param orient Orientation of the triangle.
*/
virtual void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient) = 0;
+ virtual void drawTriangleClip(int x, int y, int base, int height, TriangleOrientation orient, Common::Rect clipping) = 0;
/**
* Draws a beveled square like the ones in the Classic GUI themes.
@@ -199,6 +204,7 @@ public:
* @param bevel Amount of bevel. Must be positive.
*/
virtual void drawBeveledSquare(int x, int y, int w, int h, int bevel) = 0;
+ virtual void drawBeveledSquareClip(int x, int y, int w, int h, int bevel, Common::Rect clipping) = 0;
/**
* Draws a tab-like shape, specially thought for the Tab widget.
@@ -212,6 +218,7 @@ public:
* @param r Radius of the corners of the tab (0 for squared tabs).
*/
virtual void drawTab(int x, int y, int r, int w, int h) = 0;
+ virtual void drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping) = 0;
/**
@@ -222,6 +229,11 @@ public:
drawLine(x + w, y, x, y + h);
}
+ virtual void drawCrossClip(int x, int y, int w, int h, Common::Rect clipping) {
+ drawLineClip(x, y, x + w, y + w, clipping);
+ drawLineClip(x + w, y, x, y + h, clipping);
+ }
+
/**
* Set the active foreground painting color for the renderer.
* All the foreground drawing from then on will be done with that color, unless
@@ -278,6 +290,7 @@ public:
* Defaults to using the active Foreground color for filling.
*/
virtual void fillSurface() = 0;
+ virtual void fillSurfaceClip(Common::Rect clipping) = 0;
/**
* Clears the active surface.
@@ -355,68 +368,68 @@ public:
/**
* DrawStep callback functions for each drawing feature
*/
- void drawCallback_CIRCLE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_CIRCLE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h, radius;
radius = stepGetRadius(step, area);
stepGetPositions(step, area, x, y, w, h);
- drawCircle(x + radius, y + radius, radius);
+ drawCircleClip(x + radius, y + radius, radius, clip);
}
- void drawCallback_SQUARE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_SQUARE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawSquare(x, y, w, h);
+ drawSquareClip(x, y, w, h, clip);
}
- void drawCallback_LINE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_LINE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawLine(x, y, x + w, y + w);
+ drawLineClip(x, y, x + w, y + w, clip);
}
- void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawRoundedSquare(x, y, stepGetRadius(step, area), w, h);
+ drawRoundedSquareClip(x, y, stepGetRadius(step, area), w, h, clip);
}
- void drawCallback_FILLSURFACE(const Common::Rect &area, const DrawStep &step) {
- fillSurface();
+ void drawCallback_FILLSURFACE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
+ fillSurfaceClip(clip);
}
- void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawTriangle(x, y, w, h, (TriangleOrientation)step.extraData);
+ drawTriangleClip(x, y, w, h, (TriangleOrientation)step.extraData, clip);
}
- void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawBeveledSquare(x, y, w, h, _bevel);
+ drawBeveledSquareClip(x, y, w, h, _bevel, clip);
}
- void drawCallback_TAB(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_TAB(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawTab(x, y, stepGetRadius(step, area), w, h);
+ drawTabClip(x, y, stepGetRadius(step, area), w, h, clip);
}
- void drawCallback_BITMAP(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_BITMAP(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- blitAlphaBitmap(step.blitSrc, Common::Rect(x, y, x + w, y + h));
+ blitAlphaBitmapClip(step.blitSrc, Common::Rect(x, y, x + w, y + h), clip);
}
- void drawCallback_CROSS(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_CROSS(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawCross(x, y, w, h);
+ drawCrossClip(x, y, w, h, clip);
}
- void drawCallback_VOID(const Common::Rect &area, const DrawStep &step) {}
+ void drawCallback_VOID(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {}
/**
* Draws the specified draw step on the screen.
@@ -426,6 +439,7 @@ public:
* @param step Pointer to a DrawStep struct.
*/
virtual void drawStep(const Common::Rect &area, const DrawStep &step, uint32 extra = 0);
+ virtual void drawStepClip(const Common::Rect &area, const Common::Rect &clip, const DrawStep &step, uint32 extra = 0);
/**
* Copies the part of the current frame to the system overlay.
@@ -466,8 +480,10 @@ public:
* blitted into the active surface, at the position specified by "r".
*/
virtual void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) = 0;
+ virtual void blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) = 0;
virtual void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) = 0;
+ virtual void blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) = 0;
/**
* Draws a string into the screen. Wrapper for the Graphics::Font string drawing
diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp
index 26f0ced625..fc741f6e77 100644
--- a/graphics/VectorRendererSpec.cpp
+++ b/graphics/VectorRendererSpec.cpp
@@ -108,6 +108,33 @@ inline frac_t fp_sqroot(uint32 x) {
BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py); \
} while (0)
+#define BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
+ if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
+ *(ptr1 + (y) - (px)) = color; \
+ if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
+ *(ptr1 + (x) - (py)) = color; \
+ if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
+ *(ptr2 - (x) - (py)) = color; \
+ if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
+ *(ptr2 - (y) - (px)) = color; \
+} while (0)
+
+#define BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
+ if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
+ *(ptr3 - (y) + (px)) = color; \
+ if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
+ *(ptr3 - (x) + (py)) = color; \
+ if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
+ *(ptr4 + (x) + (py)) = color; \
+ if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
+ *(ptr4 + (y) + (px)) = color; \
+} while (0)
+
+#define BE_DRAWCIRCLE_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
+ BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
+ BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color1; \
*(ptr1 + (x) - (py)) = color1; \
@@ -119,6 +146,25 @@ inline frac_t fp_sqroot(uint32 x) {
*(ptr4 + (y) + (px)) = color2; \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
+ if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
+ *(ptr1 + (y) - (px)) = color1; \
+ if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
+ *(ptr1 + (x) - (py)) = color1; \
+ if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
+ *(ptr2 - (x) - (py)) = color1; \
+ if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
+ *(ptr2 - (y) - (px)) = color1; \
+ if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
+ *(ptr3 - (y) + (px)) = color1; \
+ if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
+ *(ptr3 - (x) + (py)) = color1; \
+ if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
+ *(ptr4 + (x) + (py)) = color2; \
+ if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
+ *(ptr4 + (y) + (px)) = color2; \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (y) - (px), color, a); \
} while (0)
@@ -127,6 +173,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr + (x) - (py), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (y), (realY) - (x))) \
+ this->blendPixelPtr(ptr + (y) - (px), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (x), (realY) - (y))) \
+ this->blendPixelPtr(ptr + (x) - (py), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (x) - (py), color, a); \
} while (0)
@@ -135,6 +191,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr - (y) - (px), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (x), (realY) - (y))) \
+ this->blendPixelPtr(ptr - (x) - (py), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (y), (realY) - (x))) \
+ this->blendPixelPtr(ptr - (y) - (px), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (y) + (px), color, a); \
} while (0)
@@ -143,6 +209,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr - (x) + (py), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (y), (realY) + (x))) \
+ this->blendPixelPtr(ptr - (y) + (px), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (x), (realY) + (y))) \
+ this->blendPixelPtr(ptr - (x) + (py), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (x) + (py), color, a); \
} while (0)
@@ -151,6 +227,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr + (y) + (px), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (x), (realY) + (y))) \
+ this->blendPixelPtr(ptr + (x) + (py), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (y), (realY) + (x))) \
+ this->blendPixelPtr(ptr + (y) + (px), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color1; \
*(ptr1 + (x) - (py)) = color2; \
@@ -170,6 +256,42 @@ inline frac_t fp_sqroot(uint32 x) {
BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py); \
} while (0)
+#define IS_IN_CLIP(x,y) (_clippingArea.left <= (x) && (x) < _clippingArea.right \
+ && _clippingArea.top <= (y) && (y) < _clippingArea.bottom)
+
+#define BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
+ if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
+ *(ptr1 + (y) - (px)) = color1; \
+\
+ if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
+ *(ptr1 + (x) - (py)) = color2; \
+\
+ if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
+ *(ptr2 - (x) - (py)) = color2; \
+\
+ if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
+ *(ptr2 - (y) - (px)) = color1; \
+} while (0)
+
+#define BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
+ if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
+ *(ptr3 - (y) + (px)) = color3; \
+\
+ if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
+ *(ptr3 - (x) + (py)) = color4; \
+\
+ if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
+ *(ptr4 + (x) + (py)) = color4; \
+\
+ if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
+ *(ptr4 + (y) + (px)) = color3; \
+} while (0)
+
+#define BE_DRAWCIRCLE_XCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
+ BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
+ BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
+} while (0)
+
#define BE_RESET() do { \
f = 1 - r; \
@@ -337,6 +459,45 @@ void colorFill(PixelType *first, PixelType *last, PixelType color) {
}
}
+template<typename PixelType>
+void colorFillClip(PixelType *first, PixelType *last, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
+ if (realY < clippingArea.top || realY >= clippingArea.bottom)
+ return;
+
+ register int count = (last - first);
+
+ if (realX > clippingArea.right || realX + count < clippingArea.left)
+ return;
+
+ if (realX < clippingArea.left) {
+ register int diff = (clippingArea.left - realX);
+ realX += diff;
+ count -= diff;
+ }
+
+ if (clippingArea.right <= realX + count) {
+ register int diff = (realX + count - clippingArea.right);
+ count -= diff;
+ }
+
+ if (!count)
+ return;
+
+ register int n = (count + 7) >> 3;
+ switch (count % 8) {
+ case 0: do {
+ *first++ = color;
+ case 7: *first++ = color;
+ case 6: *first++ = color;
+ case 5: *first++ = color;
+ case 4: *first++ = color;
+ case 3: *first++ = color;
+ case 2: *first++ = color;
+ case 1: *first++ = color;
+ } while (--n > 0);
+ }
+}
+
VectorRenderer *createRenderer(int mode) {
#ifdef DISABLE_FANCY_THEMES
@@ -376,6 +537,7 @@ VectorRendererSpec(PixelFormat format) :
_alphaMask((0xFF >> format.aLoss) << format.aShift) {
_bitmapAlphaColor = _format.RGBToColor(255, 0, 255);
+ _clippingArea = Common::Rect(0, 0, 32767, 32767);
}
/****************************
@@ -480,6 +642,49 @@ gradientFill(PixelType *ptr, int width, int x, int y) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+gradientFillClip(PixelType *ptr, int width, int x, int y, int realX, int realY) {
+ if (realY < _clippingArea.top || realY >= _clippingArea.bottom) return;
+ bool ox = ((y & 1) == 1);
+ int curGrad = 0;
+
+ while (_gradIndexes[curGrad + 1] <= y)
+ curGrad++;
+
+ // precalcGradient assures that _gradIndexes entries always differ in
+ // their value. This assures stripSize is always different from zero.
+ int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad];
+
+ int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
+
+ // Dithering:
+ // +--+ +--+ +--+ +--+
+ // | | | | | *| | *|
+ // | | | *| |* | |**|
+ // +--+ +--+ +--+ +--+
+ // 0 1 2 3
+ if (grad == 0 ||
+ _gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
+ stripSize < 2) { // the stip is small
+ colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]);
+ } else if (grad == 3 && ox) {
+ colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]);
+ } else {
+ for (int j = x; j < x + width; j++, ptr++) {
+ if (realX + j - x < _clippingArea.left || realX + j - x >= _clippingArea.right) continue;
+ bool oy = ((j & 1) == 1);
+
+ if ((ox && oy) ||
+ ((grad == 2 || grad == 3) && ox && !oy) ||
+ (grad == 3 && oy))
+ *ptr = _gradCache[curGrad + 1];
+ else
+ *ptr = _gradCache[curGrad];
+ }
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
fillSurface() {
byte *ptr = (byte *)_activeSurface->getPixels();
@@ -503,6 +708,44 @@ fillSurface() {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+fillSurfaceClip(Common::Rect clipping) {
+ int w = _activeSurface->w;
+ int h = _activeSurface->h;
+ if (clipping.isEmpty() || (clipping.left == 0 && clipping.top == 0 && clipping.right == w && clipping.bottom == h)) {
+ fillSurface();
+ return;
+ }
+
+ byte *ptr = (byte *)_activeSurface->getPixels();
+ int pitch = _activeSurface->pitch;
+
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillForeground) {
+ PixelType color = (Base::_fillMode == kFillBackground ? _bgColor : _fgColor);
+ byte *ptrLeft = (ptr + _clippingArea.left), *ptrRight = ptr + _clippingArea.right;
+ for (int i = 0; i < h; i++) {
+ if (_clippingArea.top <= i && i < _clippingArea.bottom) {
+ colorFill<PixelType>((PixelType *)ptrLeft, (PixelType *)ptrRight, color);
+ }
+
+ ptrLeft += pitch;
+ ptrRight += pitch;
+ }
+
+ } else if (Base::_fillMode == kFillGradient) {
+ precalcGradient(h);
+
+ for (int i = 0; i < h; i++) {
+ if (_clippingArea.top <= i && i < _clippingArea.bottom) {
+ gradientFill((PixelType *)ptr + _clippingArea.left, _clippingArea.width(), 0, i);
+ }
+
+ ptr += pitch;
+ }
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
copyFrame(OSystem *sys, const Common::Rect &r) {
sys->copyRectToOverlay(
@@ -554,6 +797,58 @@ blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) {
+ if (clipping.isEmpty() || clipping.contains(r)) {
+ blitSubSurface(source, r);
+ return;
+ }
+
+ int16 x = r.left;
+ int16 y = r.top;
+
+ if (r.width() > source->w)
+ x = x + (r.width() >> 1) - (source->w >> 1);
+
+ if (r.height() > source->h)
+ y = y + (r.height() >> 1) - (source->h >> 1);
+
+ int w = source->w, h = source->h;
+ int usedW = w, usedH = h;
+ int offsetX = 0, offsetY = 0;
+
+ if (x > clipping.right || x + w < clipping.left) return;
+ if (y > clipping.bottom || y + h < clipping.top) return;
+ if (x < clipping.left) {
+ offsetX = clipping.left - x;
+ usedW -= offsetX;
+ x = clipping.left;
+ }
+ if (y < clipping.top) {
+ offsetY = clipping.top - y;
+ usedH -= offsetY;
+ y = clipping.top;
+ }
+ if (usedW > clipping.width()) usedW = clipping.width();
+ if (usedH > clipping.height()) usedH = clipping.height();
+
+ byte *dst_ptr = (byte *)_activeSurface->getBasePtr(x, y);
+ const byte *src_ptr = (const byte *)source->getBasePtr(offsetX, offsetY);
+
+ const int dst_pitch = _activeSurface->pitch;
+ const int src_pitch = source->pitch;
+
+ int lines = usedH;
+ const int sz = usedW * sizeof(PixelType);
+
+ while (lines--) {
+ memcpy(dst_ptr, src_ptr, sz);
+ dst_ptr += dst_pitch;
+ src_ptr += src_pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) {
int16 x = r.left;
int16 y = r.top;
@@ -590,6 +885,65 @@ blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) {
+ if (clipping.isEmpty() || clipping.contains(r)) {
+ blitAlphaBitmap(source, r);
+ return;
+ }
+
+ int16 x = r.left;
+ int16 y = r.top;
+
+ if (r.width() > source->w)
+ x = x + (r.width() >> 1) - (source->w >> 1);
+
+ if (r.height() > source->h)
+ y = y + (r.height() >> 1) - (source->h >> 1);
+
+ int w = source->w, h = source->h;
+ int usedW = w, usedH = h;
+ int offsetX = 0, offsetY = 0;
+
+ if (x > clipping.right || x + w < clipping.left) return;
+ if (y > clipping.bottom || y + h < clipping.top) return;
+ if (x < clipping.left) {
+ offsetX = clipping.left - x;
+ usedW -= offsetX;
+ x = clipping.left;
+ }
+ if (y < clipping.top) {
+ offsetY = clipping.top - y;
+ usedH -= offsetY;
+ y = clipping.top;
+ }
+ if (usedW > clipping.width()) usedW = clipping.width();
+ if (usedH > clipping.height()) usedH = clipping.height();
+
+ PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ const PixelType *src_ptr = (const PixelType *)source->getBasePtr(offsetX, offsetY);
+
+ int dst_pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int src_pitch = source->pitch / source->format.bytesPerPixel;
+
+ h = usedH;
+ while (h--) {
+ w = usedW;
+
+ while (w--) {
+ if (*src_ptr != _bitmapAlphaColor)
+ *dst_ptr = *src_ptr;
+
+ dst_ptr++;
+ src_ptr++;
+ }
+
+ dst_ptr = dst_ptr - usedW + dst_pitch;
+ src_ptr = src_ptr - usedW + src_pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) {
int pixels = _activeSurface->w * _activeSurface->h;
PixelType *ptr = (PixelType *)_activeSurface->getPixels();
@@ -667,6 +1021,13 @@ blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) {
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
+blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y) {
+ if (IS_IN_CLIP(x, y))
+ blendPixelPtr(ptr, color, alpha);
+}
+
+template<typename PixelType>
+inline void VectorRendererSpec<PixelType>::
blendPixelDestAlphaPtr(PixelType *ptr, PixelType color, uint8 alpha) {
int idst = *ptr;
// This function is only used for corner pixels in rounded rectangles, so
@@ -710,6 +1071,36 @@ darkenFill(PixelType *ptr, PixelType *end) {
}
}
+template<typename PixelType>
+inline void VectorRendererSpec<PixelType>::
+darkenFillClip(PixelType *ptr, PixelType *end, int x, int y) {
+ PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift));
+
+ if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
+ // !kFeatureOverlaySupportsAlpha (but might have alpha bits)
+
+ while (ptr != end) {
+ if (IS_IN_CLIP(x, y)) *ptr = ((*ptr & ~mask) >> 2) | _alphaMask;
+ ++ptr;
+ ++x;
+ }
+ } else {
+ // kFeatureOverlaySupportsAlpha
+ // assuming at least 3 alpha bits
+
+ mask |= 3 << _format.aShift;
+ PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss));
+
+ while (ptr != end) {
+ // Darken the color, and increase the alpha
+ // (0% -> 75%, 100% -> 100%)
+ if (IS_IN_CLIP(x, y)) *ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA);
+ ++ptr;
+ ++x;
+ }
+ }
+}
+
/********************************************************************
********************************************************************
* Primitive shapes drawing - Public API calls - VectorRendererSpec *
@@ -818,6 +1209,77 @@ drawLine(int x1, int y1, int x2, int y2) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) {
+ x1 = CLIP(x1, 0, (int)Base::_activeSurface->w);
+ x2 = CLIP(x2, 0, (int)Base::_activeSurface->w);
+ y1 = CLIP(y1, 0, (int)Base::_activeSurface->h);
+ y2 = CLIP(y2, 0, (int)Base::_activeSurface->h);
+
+ // we draw from top to bottom
+ if (y2 < y1) {
+ SWAP(x1, x2);
+ SWAP(y1, y2);
+ }
+
+ uint dx = ABS(x2 - x1);
+ uint dy = ABS(y2 - y1);
+
+ // this is a point, not a line. stoopid.
+ if (dy == 0 && dx == 0)
+ return;
+
+ if (Base::_strokeWidth == 0)
+ return;
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int st = Base::_strokeWidth >> 1;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool needsClipping = !_clippingArea.isEmpty() && (!_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2));
+ if (!needsClipping) {
+ drawLine(x1, y1, x2, y2);
+ _clippingArea = backup;
+ return;
+ }
+
+ int ptr_x = x1, ptr_y = y1;
+
+ if (dy == 0) { // horizontal lines
+ colorFillClip<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor, x1, y1, _clippingArea);
+
+ for (int i = 0, p = pitch; i < st; ++i, p += pitch) {
+ colorFillClip<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor, x1, y1 + p/pitch, _clippingArea);
+ colorFillClip<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor, x1, y1 - p/pitch, _clippingArea);
+ }
+
+ } else if (dx == 0) { // vertical lines
+ // these ones use a static pitch increase.
+ while (y1++ <= y2) {
+ colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, x1 - st, ptr_y, _clippingArea);
+ ptr += pitch;
+ ++ptr_y;
+ }
+
+ } else if (dx == dy) { // diagonal lines
+ // these ones also use a fixed pitch increase
+ pitch += (x2 > x1) ? 1 : -1;
+
+ while (dy--) {
+ colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, ptr_x - st, ptr_y, _clippingArea);
+ ptr += pitch;
+ ++ptr_y;
+ if (x2 > x1) ++ptr_x; else --ptr_x;
+ }
+
+ } else { // generic lines, use the standard algorithm...
+ drawLineAlgClip(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
+ }
+}
+
/** CIRCLES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -857,6 +1319,70 @@ drawCircle(int x, int y, int r) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawCircleClip(int x, int y, int r, Common::Rect clipping) {
+ if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h ||
+ x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x - r, y - r, x + r, y + r)));
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + r + Base::_shadowOffset < Base::_activeSurface->w
+ && y + r + Base::_shadowOffset < Base::_activeSurface->h) {
+ if (useClippingVersions)
+ drawCircleAlgClip(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
+ else
+ drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth) {
+ if (useClippingVersions)
+ drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
+ else
+ drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillForeground:
+ if (useClippingVersions)
+ drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
+ else
+ drawCircleAlg(x, y, r, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ if (Base::_strokeWidth > 1) {
+ if (useClippingVersions) {
+ drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
+ drawCircleAlgClip(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
+ } else {
+ drawCircleAlg(x, y, r, _fgColor, kFillForeground);
+ drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
+ }
+ } else {
+ if (useClippingVersions) {
+ drawCircleAlgClip(x, y, r, _bgColor, kFillBackground);
+ drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
+ } else {
+ drawCircleAlg(x, y, r, _bgColor, kFillBackground);
+ drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
+ }
+ }
+ break;
+
+ case kFillGradient:
+ break;
+ }
+
+ _clippingArea = backup;
+}
+
/** SQUARES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -894,6 +1420,67 @@ drawSquare(int x, int y, int w, int h) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawSquareClip(int x, int y, int w, int h, Common::Rect clipping) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
+ w <= 0 || h <= 0 || x < 0 || y < 0)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + w + Base::_shadowOffset < Base::_activeSurface->w
+ && y + h + Base::_shadowOffset < Base::_activeSurface->h) {
+ if (useClippingVersions)
+ drawSquareShadowClip(x, y, w, h, Base::_shadowOffset);
+ else
+ drawSquareShadow(x, y, w, h, Base::_shadowOffset);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth) {
+ if (useClippingVersions)
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
+ else
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillForeground:
+ if (useClippingVersions)
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillForeground);
+ else
+ drawSquareAlg(x, y, w, h, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ if (useClippingVersions) {
+ drawSquareAlgClip(x, y, w, h, _bgColor, kFillBackground);
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
+ } else {
+ drawSquareAlg(x, y, w, h, _bgColor, kFillBackground);
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillGradient:
+ VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient);
+ if (Base::_strokeWidth) {
+ if (useClippingVersions)
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
+ else
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+ }
+
+ _clippingArea = backup;
+}
+
/** ROUNDED SQUARES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -920,6 +1507,43 @@ drawRoundedSquare(int x, int y, int r, int w, int h) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawRoundedSquareClip(int x, int y, int r, int w, int h, Common::Rect clipping) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
+ w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0)
+ return;
+
+ if ((r * 2) > w || (r * 2) > h)
+ r = MIN(w / 2, h / 2);
+
+ if (r <= 0)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useOriginal = (_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w
+ && y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h
+ && h > (Base::_shadowOffset + 1) * 2) {
+ if (useOriginal) {
+ drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset);
+ } else {
+ drawRoundedSquareShadowClip(x, y, r, w, h, Base::_shadowOffset);
+ }
+ }
+
+ if (useOriginal) {
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, Base::_fillMode);
+ } else {
+ drawRoundedSquareAlgClip(x, y, r, w, h, _fgColor, Base::_fillMode);
+ }
+
+ _clippingArea = backup;
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawTab(int x, int y, int r, int w, int h) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h)
@@ -956,6 +1580,66 @@ drawTab(int x, int y, int r, int w, int h) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
+ w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (r == 0 && Base::_bevel > 0) {
+ if (useClippingVersions)
+ drawBevelTabAlgClip(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
+ else
+ drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
+ _clippingArea = backup;
+ return;
+ }
+
+ if (r == 0) {
+ _clippingArea = backup;
+ return;
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ // FIXME: Implement this
+ _clippingArea = backup;
+ return;
+
+ case kFillGradient:
+ case kFillBackground:
+ // FIXME: This is broken for the AA renderer.
+ // See the rounded rect alg for how to fix it. (The border should
+ // be drawn before the interior, both inside drawTabAlg.)
+ if (useClippingVersions) {
+ drawTabShadowClip(x, y, w - 2, h, r);
+ drawTabAlgClip(x, y, w - 2, h, r, _bgColor, Base::_fillMode);
+ if (Base::_strokeWidth)
+ drawTabAlgClip(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
+ } else {
+ drawTabShadow(x, y, w - 2, h, r);
+ drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode);
+ if (Base::_strokeWidth)
+ drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF));
+ }
+ break;
+
+ case kFillForeground:
+ if (useClippingVersions)
+ drawTabAlgClip(x, y, w, h, r, _fgColor, Base::_fillMode);
+ else
+ drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode);
+ break;
+ }
+
+ _clippingArea = backup;
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
@@ -1022,8 +1706,88 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawTriangleClip(int x, int y, int w, int h, TriangleOrientation orient, Common::Rect clipping) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
+ return;
+ PixelType color = 0;
+ if (Base::_strokeWidth <= 1) {
+ if (Base::_fillMode == kFillForeground)
+ color = _fgColor;
+ else if (Base::_fillMode == kFillBackground)
+ color = _bgColor;
+ } else {
+ if (Base::_fillMode == kFillDisabled)
+ return;
+ color = _fgColor;
+ }
+
+ if (Base::_dynamicData != 0)
+ orient = (TriangleOrientation)Base::_dynamicData;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (w == h) {
+ int newW = w;
+
+ switch (orient) {
+ case kTriangleUp:
+ case kTriangleDown:
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ else
+ drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ break;
+
+ case kTriangleLeft:
+ case kTriangleRight:
+ case kTriangleAuto:
+ break;
+ }
+
+ if (Base::_strokeWidth > 0)
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ else
+ drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ }
+ } else {
+ int newW = w;
+ int newH = h;
+
+ switch (orient) {
+ case kTriangleUp:
+ case kTriangleDown:
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
+ else
+ drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
+ break;
+
+ case kTriangleLeft:
+ case kTriangleRight:
+ case kTriangleAuto:
+ break;
+ }
+
+ if (Base::_strokeWidth > 0) {
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
+ else
+ drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
+ }
+ }
+ }
+
+ _clippingArea = backup;
+}
/********************************************************************
@@ -1134,6 +1898,120 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer:
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawTabAlgClip(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) {
+ // Don't draw anything for empty rects.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int sw = 0, sp = 0, hp = 0;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+ int tl_x = x1 + r, tl_y = y1 + r;
+ int tr_x = x1 + w - r, tr_y = y1 + r;
+ int fill_x = x1, fill_y = y1;
+
+ int real_radius = r;
+ int short_h = h - r + 2;
+ int long_h = h;
+
+ if (fill_m == kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ colorFillClip<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, fill_x + r, fill_y + sp/pitch, _clippingArea);
+ colorFillClip<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, fill_x + r, fill_y + hp / pitch - sp / pitch, _clippingArea);
+ sp += pitch;
+
+ BE_RESET();
+ r--;
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+ BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
+
+ if (Base::_strokeWidth > 1)
+ BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px - pitch, py, tr_x, tr_y, tl_x, tl_y);
+ }
+ }
+
+ ptr_fill += pitch * real_radius;
+ fill_y += real_radius;
+ while (short_h--) {
+ colorFillClip<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color, fill_x, fill_y, _clippingArea);
+ colorFillClip<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, fill_x + w - Base::_strokeWidth + 1, fill_y, _clippingArea);
+ ptr_fill += pitch;
+ ++fill_y;
+ }
+
+ if (baseLeft) {
+ sw = 0;
+ ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1);
+ fill_x = x1;
+ fill_y = y1 + h + 1;
+ while (sw++ < Base::_strokeWidth) {
+ colorFillClip<PixelType>(ptr_fill - baseLeft, ptr_fill, color, fill_x - baseLeft, fill_y, _clippingArea);
+ ptr_fill += pitch;
+ ++fill_y;
+ }
+ }
+
+ if (baseRight) {
+ sw = 0;
+ ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1);
+ fill_x = x1 + w;
+ fill_y = y1 + h + 1;
+ while (sw++ < Base::_strokeWidth) {
+ colorFillClip<PixelType>(ptr_fill, ptr_fill + baseRight, color, fill_x, fill_y, _clippingArea);
+ ptr_fill += pitch;
+ ++fill_y;
+ }
+ }
+ } else {
+ BE_RESET();
+
+ precalcGradient(long_h);
+
+ PixelType color1, color2;
+ color1 = color2 = color;
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ if (fill_m == kFillGradient) {
+ color1 = calcGradient(real_radius - x, long_h);
+ color2 = calcGradient(real_radius - y, long_h);
+
+ gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y, tl_x - x, tl_y - y);
+ gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x, tl_x - y, tl_y - x);
+
+ BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
+ } else {
+ colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color, tl_x - x, tl_y - y, _clippingArea);
+ colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color, tl_x - y, tl_y - x, _clippingArea);
+
+ BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ fill_y += r;
+ while (short_h--) {
+ if (fill_m == kFillGradient) {
+ gradientFillClip(ptr_fill, w + 1, x1, real_radius++, fill_x, fill_y);
+ } else {
+ colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color, fill_x, fill_y, _clippingArea);
+ }
+ ptr_fill += pitch;
+ ++fill_y;
+ }
+ }
+}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1196,6 +2074,72 @@ drawTabShadow(int x1, int y1, int w, int h, int r) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawTabShadowClip(int x1, int y1, int w, int h, int r) {
+ int offset = 3;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+
+ // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
+ uint8 expFactor = 3;
+ uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
+
+ int xstart = x1;
+ int ystart = y1;
+ int width = w;
+ int height = h + offset + 1;
+
+ for (int i = offset; i >= 0; i--) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart);
+
+ int tl_x = xstart + r, tl_y = ystart + r;
+ int fill_x = xstart, fill_y = ystart;
+
+ int short_h = height - (2 * r) + 2;
+ PixelType color = _format.RGBToColor(0, 0, 0);
+
+ BE_RESET();
+
+ // HACK: As we are drawing circles exploting 8-axis symmetry,
+ // there are 4 pixels on each circle which are drawn twice.
+ // this is ok on filled circles, but when blending on surfaces,
+ // we cannot let it blend twice. awful.
+ uint32 hb = 0;
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ if (((1 << x) & hb) == 0) {
+ blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, tl_x - y, tl_y - x);
+ hb |= (1 << x);
+ }
+
+ if (((1 << y) & hb) == 0) {
+ blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, tl_x - x, tl_y - y);
+ hb |= (1 << y);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ fill_y += r;
+ while (short_h--) {
+ blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, fill_x, fill_y);
+ ptr_fill += pitch;
+ ++fill_y;
+ }
+
+ // Move shadow one pixel upward each iteration
+ xstart += 1;
+ // Multiply with expfactor
+ alpha = (alpha * (expFactor << 8)) >> 9;
+ }
+}
+
/** BEVELED TABS FOR CLASSIC THEME **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1240,6 +2184,57 @@ drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, Pixe
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawBevelTabAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) {
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int i, j;
+
+ PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ int ptr_x = x, ptr_y = y;
+
+ i = bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ if (baseLeft > 0) {
+ i = h - bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ ptr_x = x; ptr_y = y;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+ }
+
+ i = h - bevel;
+ j = bevel - 1;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
+ ptr_x = x + w - bevel; ptr_y = y;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
+ if (j > 0) j--;
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ i = bevel;
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel);
+ ptr_x = x + w - bevel; ptr_y = y + h - bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color, ptr_x, ptr_y, _clippingArea);
+
+ if (baseLeft)
+ colorFillClip<PixelType>(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color, ptr_x - w - baseLeft + bevel, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+}
+
/** SQUARE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1278,6 +2273,46 @@ drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillM
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawSquareAlgClip(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Do not draw anything for empty rects.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int max_h = h;
+ int ptr_y = y;
+
+ if (fill_m != kFillDisabled) {
+ while (h--) {
+ if (fill_m == kFillGradient)
+ color = calcGradient(max_h - h, max_h);
+
+ colorFillClip<PixelType>(ptr, ptr + w, color, x, ptr_y, _clippingArea);
+ ptr += pitch;
+ ++ptr_y;
+ }
+ } else {
+ int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
+
+ while (sw--) {
+ colorFillClip<PixelType>(ptr + sp, ptr + w + sp, color, x, ptr_y + sp/pitch, _clippingArea);
+ colorFillClip<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color, x, ptr_y + h - sp/pitch, _clippingArea);
+ sp += pitch;
+ }
+
+ while (h--) {
+ colorFillClip<PixelType>(ptr, ptr + Base::_strokeWidth, color, x, ptr_y, _clippingArea);
+ colorFillClip<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color, x + w - Base::_strokeWidth, ptr_y, _clippingArea);
+ ptr += pitch;
+ ptr_y += 1;
+ }
+ }
+}
+
/** SQUARE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1334,6 +2369,72 @@ drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, P
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawBevelSquareAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, bool fill) {
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int i, j;
+ PixelType *ptr_left;
+ int ptr_x, ptr_y;
+
+ // Fill Background
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ ptr_x = x; ptr_y = y;
+ i = h;
+ if (fill) {
+ assert((_bgColor & ~_alphaMask) == 0); // only support black
+ while (i--) {
+ darkenFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+ }
+
+ x = MAX(x - bevel, 0);
+ y = MAX(y - bevel, 0);
+
+ w = MIN(w + (bevel * 2), (int)_activeSurface->w);
+ h = MIN(h + (bevel * 2), (int)_activeSurface->h);
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ ptr_x = x; ptr_y = y;
+ i = bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
+ ptr_x = x; ptr_y = y + bevel;
+ i = h - bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
+ ptr_x = x; ptr_y = y + h - bevel;
+ i = bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left + i, ptr_left + w, bottom_color, ptr_x + i, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
+ ptr_x = x + w - bevel; ptr_y = y;
+ i = h - bevel;
+ j = bevel - 1;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
+ if (j > 0) j--;
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+}
+
/** GENERIC LINE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1382,6 +2483,59 @@ drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
*ptr = (PixelType)color;
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawLineAlgClip(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int xdir = (x2 > x1) ? 1 : -1;
+ int ptr_x = x1, ptr_y = y1;
+
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+
+ if (dx > dy) {
+ int ddy = dy * 2;
+ int dysub = ddy - (dx * 2);
+ int error_term = ddy - dx;
+
+ while (dx--) {
+ if (error_term >= 0) {
+ ptr += pitch;
+ ++ptr_y;
+ error_term += dysub;
+ } else {
+ error_term += ddy;
+ }
+
+ ptr += xdir;
+ ptr_x += xdir;
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+ }
+ } else {
+ int ddx = dx * 2;
+ int dxsub = ddx - (dy * 2);
+ int error_term = ddx - dy;
+
+ while (dy--) {
+ if (error_term >= 0) {
+ ptr += xdir;
+ ptr_x += xdir;
+ error_term += dxsub;
+ } else {
+ error_term += ddx;
+ }
+
+ ptr += pitch;
+ ++ptr_y;
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+ }
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
+ ptr_x = x2; ptr_y = y2;
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+}
+
/** VERTICAL TRIANGLE DRAWING ALGORITHM **/
/**
FIXED POINT ARITHMETIC
@@ -1580,6 +2734,212 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
}
+/////////////
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawTriangleVertAlgClip(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Don't draw anything for empty rects. This assures dy is always different
+ // from zero.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int gradient_h = 0;
+ int y_pitch_sign = 1;
+ if (!inverted) {
+ pitch = -pitch;
+ y1 += h;
+ y_pitch_sign = -1;
+ }
+
+ PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ PixelType *floor = ptr_right - 1;
+ PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
+
+ int x2 = x1 + w / 2;
+ int y2 = y1 + h;
+ int x_right = x1;
+ int y_right = y1;
+ int x_left = x1 + w;
+ int y_left = y1;
+ int x_floor = x_right - 1;
+ int y_floor = y_right;
+
+#if FIXED_POINT
+ int dx = (x2 - x1) << 8;
+ int dy = (y2 - y1) << 8;
+
+ if (abs(dx) > abs(dy)) {
+#else
+ double dx = (double)x2 - (double)x1;
+ double dy = (double)y2 - (double)y1;
+
+ if (fabs(dx) > fabs(dy)) {
+#endif
+ while (floor++ != ptr_left)
+ blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
+
+#if FIXED_POINT
+ // In this branch dx is always different from zero. This is because
+ // abs(dx) is strictly greater than abs(dy), and abs returns zero
+ // as minimal value.
+ int gradient = (dy << 8) / dx;
+ int intery = (y1 << 8) + gradient;
+#else
+ double gradient = dy / dx;
+ double intery = y1 + gradient;
+#endif
+
+ for (int x = x1 + 1; x < x2; x++) {
+#if FIXED_POINT
+ if (intery + gradient > ipart(intery) + 0x100) {
+#else
+ if (intery + gradient > ipart(intery) + 1) {
+#endif
+ ptr_right++;
+ ptr_left--;
+ ++x_right;
+ --x_left;
+ }
+
+ ptr_left += pitch;
+ ptr_right += pitch;
+ y_right += y_pitch_sign;
+ y_left += y_pitch_sign;
+
+ intery += gradient;
+
+ switch (fill_m) {
+ case kFillDisabled:
+ if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
+ if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
+ break;
+ case kFillForeground:
+ case kFillBackground:
+ colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
+ break;
+ case kFillGradient:
+ colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
+ break;
+ }
+ }
+
+ return;
+ }
+
+#if FIXED_POINT
+ if (abs(dx) < abs(dy)) {
+#else
+ if (fabs(dx) < fabs(dy)) {
+#endif
+ ptr_left--;
+ --x_left;
+ while (floor++ != ptr_left)
+ blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
+
+#if FIXED_POINT
+ int gradient = (dx << 8) / (dy + 0x100);
+ int interx = (x1 << 8) + gradient;
+#else
+ double gradient = dx / (dy + 1);
+ double interx = x1 + gradient;
+#endif
+
+ for (int y = y1 + 1; y < y2; y++) {
+#if FIXED_POINT
+ if (interx + gradient > ipart(interx) + 0x100) {
+#else
+ if (interx + gradient > ipart(interx) + 1) {
+#endif
+ ptr_right++;
+ ptr_left--;
+ ++x_right;
+ --x_left;
+ }
+
+ ptr_left += pitch;
+ ptr_right += pitch;
+ y_right += y_pitch_sign;
+ y_left += y_pitch_sign;
+
+ interx += gradient;
+
+ switch (fill_m) {
+ case kFillDisabled:
+ if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
+ if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
+ break;
+ case kFillForeground:
+ case kFillBackground:
+ colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ case kFillGradient:
+ colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ }
+ }
+
+ return;
+ }
+
+ ptr_left--;
+ --x_left;
+ while (floor++ != ptr_left)
+ blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
+
+#if FIXED_POINT
+ int gradient = (dx / dy) << 8;
+ int interx = (x1 << 8) + gradient;
+#else
+ double gradient = dx / dy;
+ double interx = x1 + gradient;
+#endif
+
+ for (int y = y1 + 1; y < y2; y++) {
+ ptr_right++;
+ ptr_left--;
+ ++x_right;
+ --x_left;
+
+ ptr_left += pitch;
+ ptr_right += pitch;
+ y_right += y_pitch_sign;
+ y_left += y_pitch_sign;
+
+ interx += gradient;
+
+ switch (fill_m) {
+ case kFillDisabled:
+ if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
+ if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
+ break;
+ case kFillForeground:
+ case kFillBackground:
+ colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ case kFillGradient:
+ colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ }
+ }
+}
+
+/////////////
+
/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1682,6 +3042,9 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
while (x++ < (y - 2)) {
BE_ALGORITHM();
+ if (x < _clippingArea.left || x > _clippingArea.right) continue;
+ if (y < _clippingArea.top || y > _clippingArea.bottom) continue;
+
BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)));
BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)));
BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)));
@@ -1709,6 +3072,74 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int sw = 0, sp = 0, hp = h * pitch;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int real_radius = r;
+ int short_h = h - (2 * r) + 2;
+
+ PixelType color1 = color;
+ PixelType color2 = color;
+
+ while (sw++ < Base::_strokeWidth) {
+ blendFillClip(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t,
+ x1 + r, y1 + sp/pitch); // top
+ blendFillClip(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b,
+ x1 + r, y1 + (hp - sp)/ pitch); // bottom
+ sp += pitch;
+
+ BE_RESET();
+ r--;
+
+ int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1));
+ int alphaStep_br = ((alpha_r - alpha_b) / (y + 1));
+ int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1));
+ int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1));
+
+ // Avoid blending the last pixels twice, since we have an alpha
+ while (x++ < (y - 2)) {
+ BE_ALGORITHM();
+
+ BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)), x1 + w - r, y1 + r);
+ BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)), x1 + w - r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)), x1 + r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)), x1 + r, y1 + r);
+
+ BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)), x1 + w - r, y1 + r);
+ BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)), x1 + w - r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)), x1 + r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)), x1 + r, y1 + r);
+
+ if (Base::_strokeWidth > 1) {
+ BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ }
+ }
+ }
+
+ ptr_fill += pitch * real_radius;
+ while (short_h--) {
+ blendFillClip(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l,
+ x1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // left
+ blendFillClip(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r,
+ x1 + w - Base::_strokeWidth + 1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // right
+ ptr_fill += pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw empty space rounded squares.
if (w <= 0 || h <= 0) {
@@ -1740,6 +3171,8 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
while (x++ < y) {
BE_ALGORITHM();
+ if (y1 + r + y < _clippingArea.top || y1 + r + y > _clippingArea.bottom) continue;
+
color1 = calcGradient(real_radius - x, long_h);
color2 = calcGradient(real_radius - y, long_h);
color3 = calcGradient(long_h - r + x, long_h);
@@ -1781,6 +3214,91 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Do not draw empty space rounded squares.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int real_radius = r;
+ int short_h = h - (2 * r) + 2;
+ int long_h = h;
+
+ BE_RESET();
+
+ PixelType color1 = color;
+
+ if (fill_m == kFillGradient) {
+ PixelType color2, color3, color4;
+ precalcGradient(long_h);
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ color1 = calcGradient(real_radius - x, long_h);
+ color2 = calcGradient(real_radius - y, long_h);
+ color3 = calcGradient(long_h - r + x, long_h);
+ color4 = calcGradient(long_h - r + y, long_h);
+
+ //TL = (x1 + r, y1 + r)
+ gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y,
+ x1 + r - x, y1 + r - y);
+ gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x,
+ x1 + r - y, y1 + r - x);
+
+ //BL = (x1 + r, y1 + h - r)
+ gradientFillClip(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y,
+ x1 + r - x, y1 + h - r + y);
+ gradientFillClip(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x,
+ x1 + r - y, y1 + h - r + x);
+
+ BE_DRAWCIRCLE_XCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ }
+ } else {
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1,
+ x1 + r - x, y1 + r - y, _clippingArea);
+ colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1,
+ x1 + r - y, y1 + r - x, _clippingArea);
+
+ colorFillClip<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1,
+ x1 + r - x, y1 + h - r + y, _clippingArea);
+ colorFillClip<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1,
+ x1 + r - y, y1 + h - r + x, _clippingArea);
+
+ // do not remove - messes up the drawing at lower resolutions
+ BE_DRAWCIRCLE_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ int short_h_orig = short_h;
+ while (short_h--) {
+ if (fill_m == kFillGradient) {
+ gradientFillClip(ptr_fill, w + 1, x1, real_radius++, x1, y1 + r + short_h_orig - short_h -1);
+ } else {
+ colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color1, x1, y1 + r + short_h_orig - short_h - 1, _clippingArea);
+ }
+ ptr_fill += pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
@@ -1810,6 +3328,38 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, Vecto
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ const uint8 borderAlpha_t = 0;
+ const uint8 borderAlpha_r = 127;
+ const uint8 borderAlpha_b = 255;
+ const uint8 borderAlpha_l = 63;
+
+ const uint8 bevelAlpha_t = 255;
+ const uint8 bevelAlpha_r = 31;
+ const uint8 bevelAlpha_b = 0;
+ const uint8 bevelAlpha_l = 127;
+
+ // If only border is visible
+ if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
+ if (fill_m == Base::kFillBackground)
+ drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, _bgColor, fill_m);
+ else
+ drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m);
+ }
+
+ //I expect these to work fine with clipping:
+ if (Base::_strokeWidth) {
+ if (r != 0 && _bevel > 0) {
+ drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
+ drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
+ } else {
+ drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
+ }
+ }
+}
+
/** CIRCLE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1854,7 +3404,47 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawCircleAlgClip(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py, sw = 0;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+ if (fill_m == kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ BE_RESET();
+ r--;
+
+ if (IS_IN_CLIP(x1 + y, y1)) *(ptr + y) = color;
+ if (IS_IN_CLIP(x1 - y, y1)) *(ptr - y) = color;
+ if (IS_IN_CLIP(x1, y1 + y)) *(ptr + py) = color;
+ if (IS_IN_CLIP(x1, y1 - y)) *(ptr - py) = color;
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+ BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
+
+ if (Base::_strokeWidth > 1) {
+ BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x - 1, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
+ BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px - pitch, py, x1, y1, x1, y1, x1, y1, x1, y1);
+ }
+ }
+ }
+ } else {
+ colorFillClip<PixelType>(ptr - r, ptr + r, color, x1 - r, y1 + r, _clippingArea);
+ BE_RESET();
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+ colorFillClip<PixelType>(ptr - x + py, ptr + x + py, color, x1 - x, y1 + y, _clippingArea);
+ colorFillClip<PixelType>(ptr - x - py, ptr + x - py, color, x1 - x, y1 - y, _clippingArea);
+ colorFillClip<PixelType>(ptr - y + px, ptr + y + px, color, x1 - y, y1 + x, _clippingArea);
+ colorFillClip<PixelType>(ptr - y - px, ptr + y - px, color, x1 - y, y1 - x, _clippingArea);
+ }
+ }
+}
/********************************************************************
@@ -1905,6 +3495,54 @@ drawSquareShadow(int x, int y, int w, int h, int offset) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawSquareShadowClip(int x, int y, int w, int h, int offset) {
+ // Do nothing for empty rects or no shadow offset.
+ if (w <= 0 || h <= 0 || offset <= 0) {
+ return;
+ }
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int i, j, ptr_x = x+w-1, ptr_y = y+offset;
+
+ i = h - offset;
+
+ while (i--) {
+ j = offset;
+ while (j--)
+ blendPixelPtrClip(ptr + j, 0, ((offset - j) << 8) / offset, ptr_x + j, ptr_y);
+ ptr += pitch;
+ ++ptr_y;
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1);
+ ptr_x = x + offset;
+ ptr_y = y + h - 1;
+
+ while (i++ < offset) {
+ j = w - offset;
+ while (j--)
+ blendPixelPtrClip(ptr + j, 0, ((offset - i) << 8) / offset, ptr_x + j, ptr_y);
+ ptr += pitch;
+ ++ptr_y;
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
+ ptr_x = x + w;
+ ptr_y = y + h;
+
+ i = 0;
+ while (i++ < offset) {
+ j = offset - 1;
+ while (j--)
+ blendPixelPtrClip(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset), ptr_x + j, ptr_y);
+ ptr += pitch;
+ ++ptr_y;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
@@ -1942,7 +3580,6 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
while (x++ < y) {
BE_ALGORITHM();
-
if (((1 << x) & hb) == 0) {
blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
@@ -1978,6 +3615,83 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) {
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+
+ // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme)
+ uint8 expFactor = 3;
+ uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8;
+
+ // These constants ensure a border of 2px on the left and of each rounded square
+ int xstart = (x1 > 2) ? x1 - 2 : x1;
+ int ystart = y1;
+ int width = w + offset + 2;
+ int height = h + offset + 1;
+
+ for (int i = offset; i >= 0; i--) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+
+ PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r);
+ PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r);
+ PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + height - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart);
+
+ int short_h = height - (2 * r) + 2;
+ PixelType color = _format.RGBToColor(0, 0, 0);
+
+ BE_RESET();
+
+ // HACK: As we are drawing circles exploting 8-axis symmetry,
+ // there are 4 pixels on each circle which are drawn twice.
+ // this is ok on filled circles, but when blending on surfaces,
+ // we cannot let it blend twice. awful.
+ uint32 hb = 0;
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ if (((1 << x) & hb) == 0) {
+ blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha,
+ xstart + r - y, ystart + r - x);
+
+ // Will create a dark line of pixles if left out
+ if (hb > 0) {
+ blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha,
+ xstart + r - y, ystart + height - r + x);
+ }
+ hb |= (1 << x);
+ }
+
+ if (((1 << y) & hb) == 0) {
+ blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, xstart + r - x, ystart + r - y);
+ blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha, xstart + r - x, ystart + height - r + y);
+ hb |= (1 << y);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ int orig_short_h = short_h;
+ while (short_h--) {
+ blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha,
+ xstart, ystart + r + orig_short_h - short_h - 1);
+ ptr_fill += pitch;
+ }
+
+ // Make shadow smaller each iteration, and move it one pixel inward
+ xstart += 1;
+ ystart += 1;
+ width -= 2;
+ height -= 2;
+
+ if (_shadowFillMode == kShadowExponential)
+ // Multiply with expfactor
+ alpha = (alpha * (expFactor << 8)) >> 9;
+ }
+}
/******************************************************************************/
@@ -2256,6 +3970,9 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
template<typename PixelType>
void VectorRendererAA<PixelType>::
drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ w -= 2*Base::_strokeWidth;
+ h -= 2*Base::_strokeWidth;
+
// Do not draw empty space rounded squares.
if (w <= 0 || h <= 0) {
return;
@@ -2272,8 +3989,6 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
r -= Base::_strokeWidth;
x1 += Base::_strokeWidth;
y1 += Base::_strokeWidth;
- w -= 2*Base::_strokeWidth;
- h -= 2*Base::_strokeWidth;
rsq = r*r;
PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r);
diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h
index 3e54608b8e..bee6d4c425 100644
--- a/graphics/VectorRendererSpec.h
+++ b/graphics/VectorRendererSpec.h
@@ -51,14 +51,31 @@ public:
VectorRendererSpec(PixelFormat format);
void drawLine(int x1, int y1, int x2, int y2);
+ void drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping);
void drawCircle(int x, int y, int r);
+ void drawCircleClip(int x, int y, int r, Common::Rect clipping);
void drawSquare(int x, int y, int w, int h);
+ void drawSquareClip(int x, int y, int w, int h, Common::Rect clipping);
void drawRoundedSquare(int x, int y, int r, int w, int h);
+ void drawRoundedSquareClip(int x, int y, int r, int w, int h, Common::Rect clipping);
void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient);
+ void drawTriangleClip(int x, int y, int base, int height, TriangleOrientation orient, Common::Rect clipping);
void drawTab(int x, int y, int r, int w, int h);
+ void drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping);
void drawBeveledSquare(int x, int y, int w, int h, int bevel) {
drawBevelSquareAlg(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
}
+ void drawBeveledSquareClip(int x, int y, int w, int h, int bevel, Common::Rect clipping) {
+ bool useClippingVersions = !(clipping.isEmpty() || clipping.contains(Common::Rect(x, y, x + w, y + h)));
+ if (useClippingVersions) {
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ drawBevelSquareAlgClip(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
+ _clippingArea = backup;
+ } else {
+ drawBevelSquareAlg(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
+ }
+ }
void drawString(const Graphics::Font *font, const Common::String &text,
const Common::Rect &area, Graphics::TextAlign alignH,
GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool elipsis, const Common::Rect &textDrawableArea = Common::Rect(0, 0, 0, 0));
@@ -72,14 +89,19 @@ public:
void copyWholeFrame(OSystem *sys) { copyFrame(sys, Common::Rect(0, 0, _activeSurface->w, _activeSurface->h)); }
void fillSurface();
+ void fillSurfaceClip(Common::Rect clipping);
void blitSurface(const Graphics::Surface *source, const Common::Rect &r);
void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r);
+ void blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping);
void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r);
+ void blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping);
void applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle);
protected:
+ Common::Rect _clippingArea;
+
/**
* Draws a single pixel on the surface with the given coordinates and
* the given color.
@@ -119,6 +141,7 @@ protected:
* @param alpha Alpha intensity of the pixel (0-255)
*/
inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha);
+ inline void blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y);
/**
* Blends a single pixel on the surface in the given pixel pointer, using supplied color
@@ -152,40 +175,74 @@ protected:
virtual void drawLineAlg(int x1, int y1, int x2, int y2,
uint dx, uint dy, PixelType color);
+ virtual void drawLineAlgClip(int x1, int y1, int x2, int y2,
+ uint dx, uint dy, PixelType color);
+
virtual void drawCircleAlg(int x, int y, int r,
PixelType color, FillMode fill_m);
+ virtual void drawCircleAlgClip(int x, int y, int r,
+ PixelType color, FillMode fill_m);
+
virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h,
PixelType color, FillMode fill_m);
+ virtual void drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m);
+
virtual void drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h,
PixelType color, FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l);
+ virtual void drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l);
+
virtual void drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h,
PixelType color, FillMode fill_m);
+ virtual void drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m);
+
virtual void drawSquareAlg(int x, int y, int w, int h,
PixelType color, FillMode fill_m);
+ virtual void drawSquareAlgClip(int x, int y, int w, int h,
+ PixelType color, FillMode fill_m);
+
virtual void drawTriangleVertAlg(int x, int y, int w, int h,
bool inverted, PixelType color, FillMode fill_m);
+ virtual void drawTriangleVertAlgClip(int x, int y, int w, int h,
+ bool inverted, PixelType color, FillMode fill_m);
+
virtual void drawTriangleFast(int x, int y, int size,
bool inverted, PixelType color, FillMode fill_m);
virtual void drawBevelSquareAlg(int x, int y, int w, int h,
int bevel, PixelType top_color, PixelType bottom_color, bool fill);
+ virtual void drawBevelSquareAlgClip(int x, int y, int w, int h,
+ int bevel, PixelType top_color, PixelType bottom_color, bool fill);
+
virtual void drawTabAlg(int x, int y, int w, int h, int r,
PixelType color, VectorRenderer::FillMode fill_m,
int baseLeft = 0, int baseRight = 0);
+ virtual void drawTabAlgClip(int x, int y, int w, int h, int r,
+ PixelType color, VectorRenderer::FillMode fill_m,
+ int baseLeft = 0, int baseRight = 0);
+
virtual void drawTabShadow(int x, int y, int w, int h, int r);
+ virtual void drawTabShadowClip(int x, int y, int w, int h, int r);
+
virtual void drawBevelTabAlg(int x, int y, int w, int h,
int bevel, PixelType topColor, PixelType bottomColor,
int baseLeft = 0, int baseRight = 0);
+ virtual void drawBevelTabAlgClip(int x, int y, int w, int h,
+ int bevel, PixelType topColor, PixelType bottomColor,
+ int baseLeft = 0, int baseRight = 0);
+
/**
* SHADOW DRAWING ALGORITHMS
*
@@ -197,7 +254,9 @@ protected:
* @param offset Intensity/size of the shadow.
*/
virtual void drawSquareShadow(int x, int y, int w, int h, int offset);
+ virtual void drawSquareShadowClip(int x, int y, int w, int h, int offset);
virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int offset);
+ virtual void drawRoundedSquareShadowClip(int x, int y, int r, int w, int h, int offset);
/**
* Calculates the color gradient on a given point.
@@ -212,6 +271,7 @@ protected:
void precalcGradient(int h);
void gradientFill(PixelType *first, int width, int x, int y);
+ void gradientFillClip(PixelType *first, int width, int x, int y, int realX, int realY);
/**
* Fills several pixels in a row with a given color and the specified alpha blending.
@@ -227,7 +287,20 @@ protected:
while (first != last) blendPixelPtr(first++, color, alpha);
}
+ inline void blendFillClip(PixelType *first, PixelType *last, PixelType color, uint8 alpha, int realX, int realY) {
+ if (_clippingArea.top <= realY && realY < _clippingArea.bottom) {
+ while (first != last) {
+ if (_clippingArea.left <= realX && realX < _clippingArea.right)
+ blendPixelPtr(first++, color, alpha);
+ else
+ ++first;
+ ++realX;
+ }
+ }
+ }
+
void darkenFill(PixelType *first, PixelType *last);
+ void darkenFillClip(PixelType *first, PixelType *last, int x, int y);
const PixelFormat _format;
const PixelType _redMask, _greenMask, _blueMask, _alphaMask;
diff --git a/graphics/font.cpp b/graphics/font.cpp
index dba48249bc..97662dc15d 100644
--- a/graphics/font.cpp
+++ b/graphics/font.cpp
@@ -21,6 +21,7 @@
*/
#include "graphics/font.h"
+#include "graphics/managed_surface.h"
#include "common/array.h"
#include "common/util.h"
@@ -264,6 +265,14 @@ int Font::getStringWidth(const Common::U32String &str) const {
return getStringWidthImpl(*this, str);
}
+void Font::drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const {
+ drawChar(&dst->_innerSurface, chr, x, y, color);
+
+ Common::Rect charBox = getBoundingBox(chr);
+ charBox.translate(x, y);
+ dst->addDirtyRect(charBox);
+}
+
void Font::drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
Common::String renderStr = useEllipsis ? handleEllipsis(str, w) : str;
drawStringImpl(*this, dst, renderStr, x, y, w, color, align, deltax);
@@ -273,6 +282,20 @@ void Font::drawString(Surface *dst, const Common::U32String &str, int x, int y,
drawStringImpl(*this, dst, str, x, y, w, color, align, 0);
}
+void Font::drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align, int deltax, bool useEllipsis) const {
+ drawString(&dst->_innerSurface, str, x, y, w, color, align, deltax, useEllipsis);
+ if (w != 0) {
+ dst->addDirtyRect(getBoundingBox(str, x, y, w, align, deltax, useEllipsis));
+ }
+}
+
+void Font::drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align) const {
+ drawString(&dst->_innerSurface, str, x, y, w, color, align);
+ if (w != 0) {
+ dst->addDirtyRect(getBoundingBox(str, x, y, w, align));
+ }
+}
+
int Font::wordWrapText(const Common::String &str, int maxWidth, Common::Array<Common::String> &lines) const {
return wordWrapTextImpl(*this, str, maxWidth, lines);
}
diff --git a/graphics/font.h b/graphics/font.h
index 35f6792d7f..0478608708 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -34,6 +34,7 @@ template<class T> class Array;
namespace Graphics {
struct Surface;
+class ManagedSurface;
/** Text alignment modes */
enum TextAlign {
@@ -141,10 +142,13 @@ public:
* @param color The color of the character.
*/
virtual void drawChar(Surface *dst, uint32 chr, int x, int y, uint32 color) const = 0;
+ void drawChar(ManagedSurface *dst, uint32 chr, int x, int y, uint32 color) const;
// TODO: Add doxygen comments to this
void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const;
+ void drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
+ void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft) const;
/**
* Compute and return the width the string str has when rendered using this font.
diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp
new file mode 100644
index 0000000000..273b15de55
--- /dev/null
+++ b/graphics/managed_surface.cpp
@@ -0,0 +1,260 @@
+/* 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.
+ *
+ */
+
+#include "graphics/managed_surface.h"
+#include "common/algorithm.h"
+#include "common/textconsole.h"
+
+namespace Graphics {
+
+const int SCALE_THRESHOLD = 0x100;
+
+ManagedSurface::ManagedSurface() :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+}
+
+ManagedSurface::ManagedSurface(ManagedSurface &surf) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ *this = surf;
+}
+
+ManagedSurface::ManagedSurface(int width, int height) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ create(width, height);
+}
+
+ManagedSurface::ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ create(width, height, pixelFormat);
+}
+
+ManagedSurface::ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds) :
+ w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format),
+ _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) {
+ create(surf, bounds);
+}
+
+ManagedSurface::~ManagedSurface() {
+ free();
+}
+
+ManagedSurface &ManagedSurface::operator=(ManagedSurface &surf) {
+ // Free any current surface
+ free();
+
+ if (surf._disposeAfterUse == DisposeAfterUse::YES) {
+ // Create a new surface and copy the pixels from the source surface
+ create(surf.w, surf.h, surf.format);
+ Common::copy((const byte *)surf.getPixels(), (const byte *)surf.getPixels() +
+ surf.w * surf.h * surf.format.bytesPerPixel, (byte *)this->getPixels());
+ } else {
+ // Source isn't managed, so simply copy its fields
+ _owner = surf._owner;
+ _offsetFromOwner = surf._offsetFromOwner;
+ void *srcPixels = surf._innerSurface.getPixels();
+ _innerSurface.setPixels(srcPixels);
+ _innerSurface.w = surf.w;
+ _innerSurface.h = surf.h;
+ _innerSurface.pitch = surf.pitch;
+ this->format = surf.format;
+ }
+
+ return *this;
+}
+
+void ManagedSurface::setPixels(void *newPixels) {
+ free();
+ _innerSurface.setPixels(newPixels);
+}
+
+void ManagedSurface::create(uint16 width, uint16 height) {
+ create(width, height, PixelFormat::createFormatCLUT8());
+}
+
+void ManagedSurface::create(uint16 width, uint16 height, const PixelFormat &pixelFormat) {
+ free();
+ _innerSurface.create(width, height, pixelFormat);
+
+ _disposeAfterUse = DisposeAfterUse::YES;
+ markAllDirty();
+}
+
+void ManagedSurface::create(ManagedSurface &surf, const Common::Rect &bounds) {
+ free();
+
+ _offsetFromOwner = Common::Point(bounds.left, bounds.top);
+ _innerSurface.setPixels(surf.getBasePtr(bounds.left, bounds.top));
+ _innerSurface.pitch = surf.pitch;
+ _innerSurface.format = surf.format;
+ _innerSurface.w = bounds.width();
+ _innerSurface.h = bounds.height();
+ _owner = &surf;
+ _disposeAfterUse = DisposeAfterUse::NO;
+}
+
+void ManagedSurface::free() {
+ if (_disposeAfterUse == DisposeAfterUse::YES)
+ _innerSurface.free();
+
+ _disposeAfterUse = DisposeAfterUse::NO;
+ _owner = nullptr;
+ _offsetFromOwner = Common::Point(0, 0);
+}
+
+bool ManagedSurface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) {
+ if (destBounds.left >= this->w || destBounds.top >= this->h ||
+ destBounds.right <= 0 || destBounds.bottom <= 0)
+ return false;
+
+ // Clip the bounds if necessary to fit on-screen
+ if (destBounds.right > this->w) {
+ srcBounds.right -= destBounds.right - this->w;
+ destBounds.right = this->w;
+ }
+
+ if (destBounds.bottom > this->h) {
+ srcBounds.bottom -= destBounds.bottom - this->h;
+ destBounds.bottom = this->h;
+ }
+
+ if (destBounds.top < 0) {
+ srcBounds.top += -destBounds.top;
+ destBounds.top = 0;
+ }
+
+ if (destBounds.left < 0) {
+ srcBounds.left += -destBounds.left;
+ destBounds.left = 0;
+ }
+
+ return true;
+}
+
+void ManagedSurface::blitFrom(const Surface &src) {
+ blitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0));
+}
+
+void ManagedSurface::blitFrom(const Surface &src, const Common::Point &destPos) {
+ blitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos);
+}
+
+void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Point &destPos) {
+ Common::Rect srcBounds = srcRect;
+ Common::Rect destBounds(destPos.x, destPos.y, destPos.x + srcRect.width(),
+ destPos.y + srcRect.height());
+ assert(src.format.bytesPerPixel == format.bytesPerPixel);
+
+ if (!srcRect.isValidRect() || !clip(srcBounds, destBounds))
+ return;
+
+ for (int y = 0; y < srcBounds.height(); ++y) {
+ const byte *srcP = (const byte *)src.getBasePtr(srcBounds.left, srcBounds.top + y);
+ byte *destP = (byte *)getBasePtr(destBounds.left, destBounds.top + y);
+ Common::copy(srcP, srcP + srcBounds.width() * format.bytesPerPixel, destP);
+ }
+
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, uint transColor, bool flipped, uint overrideColor) {
+ transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(0, 0, this->w, this->h),
+ transColor, false, overrideColor);
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos,
+ uint transColor, bool flipped, uint overrideColor) {
+ transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y,
+ destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor);
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor) {
+ transBlitFrom(src, srcRect, Common::Rect(destPos.x, destPos.y,
+ destPos.x + src.w, destPos.y + src.h), transColor, false, overrideColor);
+}
+
+template<typename T>
+void transBlit(const Surface &src, const Common::Rect &srcRect, Surface *dest, const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) {
+ int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width();
+ int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height();
+
+ // Loop through drawing output lines
+ for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) {
+ if (destY < 0 || destY >= dest->h)
+ continue;
+ const T *srcLine = (const T *)src.getBasePtr(0, scaleYCtr / SCALE_THRESHOLD);
+ T *destLine = (T *)dest->getBasePtr(destRect.left, destY);
+
+ // Loop through drawing the pixels of the row
+ for (int destX = destRect.left, xCtr = 0, scaleXCtr = 0; destX < destRect.right; ++destX, ++xCtr, scaleXCtr += scaleX) {
+ if (destX < 0 || destX >= dest->w)
+ continue;
+
+ T srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD];
+ if (srcVal != transColor) {
+ destLine[xCtr] = overrideColor ? overrideColor : srcVal;
+ }
+ }
+ }
+}
+
+void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor) {
+ if (src.w == 0 || src.h == 0 || destRect.width() == 0 || destRect.height() == 0)
+ return;
+
+ if (format.bytesPerPixel == 1)
+ transBlit<byte>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor);
+ else if (format.bytesPerPixel == 2)
+ transBlit<uint16>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor);
+ else if (format.bytesPerPixel == 4)
+ transBlit<uint32>(src, srcRect, &_innerSurface, destRect, transColor, flipped, overrideColor);
+ else
+ error("Surface::transBlitFrom: bytesPerPixel must be 1, 2, or 4");
+
+ // Mark the affected area
+ addDirtyRect(destRect);
+}
+
+void ManagedSurface::markAllDirty() {
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
+}
+
+void ManagedSurface::addDirtyRect(const Common::Rect &r) {
+ if (_owner) {
+ Common::Rect bounds = r;
+ bounds.clip(Common::Rect(0, 0, this->w, this->h));
+ bounds.translate(_offsetFromOwner.x, _offsetFromOwner.y);
+ _owner->addDirtyRect(bounds);
+ }
+}
+
+void ManagedSurface::clear(uint color) {
+ fillRect(getBounds(), color);
+}
+
+} // End of namespace Graphics
diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h
new file mode 100644
index 0000000000..8cbd463266
--- /dev/null
+++ b/graphics/managed_surface.h
@@ -0,0 +1,376 @@
+/* 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.
+ *
+ */
+
+#ifndef GRAPHICS_MANAGED_SURFACE_H
+#define GRAPHICS_MANAGED_SURFACE_H
+
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+#include "common/rect.h"
+#include "common/types.h"
+
+namespace Graphics {
+
+class Font;
+
+/**
+ * A derived graphics surface, which handles automatically managing the allocated
+ * surface data block, as well as introducing several new blitting methods
+ */
+class ManagedSurface {
+ friend class Font;
+private:
+ /**
+ * The Graphics::Surface that the managed surface encapsulates
+ */
+ Surface _innerSurface;
+
+ /**
+ * If set, the inner surface will be freed when the surface is recreated,
+ * as well as when the surface is destroyed
+ */
+ DisposeAfterUse::Flag _disposeAfterUse;
+
+ /**
+ * Stores the owning surface if this If this managed surface represents
+ * a sub-section of another
+ */
+ ManagedSurface *_owner;
+
+ /**
+ * For sub-section areas of an owning parent managed surface, this represents
+ * the offset from the parent's top-left corner this sub-surface starts at
+ */
+ Common::Point _offsetFromOwner;
+protected:
+ /**
+ * Clips the given source bounds so the passed destBounds will be entirely on-screen
+ */
+ bool clip(Common::Rect &srcBounds, Common::Rect &destBounds);
+
+ /**
+ * Base method that descendent classes can override for recording affected
+ * dirty areas of the surface
+ */
+ virtual void addDirtyRect(const Common::Rect &r);
+public:
+ uint16 &w;
+ uint16 &h;
+ uint16 &pitch;
+ PixelFormat &format;
+public:
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface();
+
+ /**
+ * Create a managed surface from another one.
+ * If the source surface is maintaining it's own surface data, then
+ * this surface will create it's own surface of the same size and copy
+ * the contents from the source surface
+ */
+ ManagedSurface(ManagedSurface &surf);
+
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface(int width, int height);
+
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat);
+
+ /**
+ * Create the managed surface
+ */
+ ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds);
+
+ /**
+ * Destroy the managed surface
+ */
+ virtual ~ManagedSurface();
+
+ /**
+ * Implements automatic conversion to a Graphics::Surface by
+ * simply returning the inner surface. This must be const,
+ * because we don't want changes being done directly to it,
+ * since it would bypass dirty rect handling
+ */
+ operator const Surface &() const { return _innerSurface; }
+ const Surface &rawSurface() const { return _innerSurface; }
+
+ /**
+ * Reassign one managed surface to another one
+ * Note that if the source has a managed surface, it will be duplicated
+ */
+ ManagedSurface &operator=(ManagedSurface &surf);
+
+ /**
+ * Returns true if the surface has not yet been allocated
+ */
+ bool empty() const { return w == 0 || h == 0 || _innerSurface.getPixels() == nullptr; }
+
+ /**
+ * Returns true if the surface is managing its own pixels
+ */
+ DisposeAfterUse::Flag disposeAfterUse() const { return _disposeAfterUse; }
+
+ /**
+ * Return a pointer to the pixel at the specified point.
+ *
+ * @param x The x coordinate of the pixel.
+ * @param y The y coordinate of the pixel.
+ * @return Pointer to the pixel.
+ */
+ inline const void *getBasePtr(int x, int y) const {
+ return _innerSurface.getBasePtr(x, y);
+ }
+
+ /**
+ * Return a pointer to the pixel at the specified point.
+ *
+ * @param x The x coordinate of the pixel.
+ * @param y The y coordinate of the pixel.
+ * @return Pointer to the pixel.
+ */
+ inline void *getBasePtr(int x, int y) {
+ return _innerSurface.getBasePtr(x, y);
+ }
+
+ /**
+ * Get a reference to the pixel data
+ */
+ inline void *getPixels() { return _innerSurface.getPixels(); }
+ inline const void *getPixels() const { return _innerSurface.getPixels(); }
+
+ /**
+ * Sets the pixel data.
+ */
+ virtual void setPixels(void *newPixels);
+
+ /**
+ * Allocate memory for the pixel data of the surface.
+ */
+ virtual void create(uint16 width, uint16 height);
+
+ /**
+ * Allocate memory for the pixel data of the surface.
+ */
+ virtual void create(uint16 width, uint16 height, const PixelFormat &pixelFormat);
+
+ /**
+ * Sets up the surface as a sub-section of another passed parent surface. This surface
+ * will not own the pixels, and any dirty rect notifications will automatically be
+ * passed to the original parent surface.
+ * @remarks Note that this differs from Graphics::Surface::getSubArea, in that that
+ * method only adds a single initial dirty rect for the whole area, and then none further
+ */
+ virtual void create(ManagedSurface &surf, const Common::Rect &bounds);
+
+ /**
+ * Release the memory used by the pixels memory of this surface. This is the
+ * counterpart to create().
+ */
+ virtual void free();
+
+ /**
+ * Clears any pending dirty rects that have been generated for the surface
+ */
+ virtual void clearDirtyRects() {}
+
+ /**
+ * When the managed surface is a sub-section of a parent surface, returns the
+ * the offset in the parent surface that the surface starts at
+ */
+ const Common::Point getOffsetFromOwner() const { return _offsetFromOwner; }
+
+ /**
+ * Return a rect giving the bounds of the surface
+ */
+ const Common::Rect getBounds() const {
+ return Common::Rect(0, 0, this->w, this->h);
+ }
+
+ /**
+ * Copies another surface into this one
+ */
+ void blitFrom(const Surface &src);
+
+ /**
+ * Copies another surface into this one at a given destination position
+ */
+ void blitFrom(const Surface &src, const Common::Point &destPos);
+
+ /**
+ * Copies another surface into this one at a given destination position
+ */
+ void blitFrom(const Surface &src, const Common::Rect &srcRect,
+ const Common::Point &destPos);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param destPos Destination position to draw the surface
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, const Common::Point &destPos,
+ uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param srcRect Sub-section of source surface to draw
+ * @param destPos Destination position to draw the surface
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos,
+ uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Copies another surface into this one ignoring pixels of a designated transparent color
+ * @param src Source surface
+ * @param srcRect Sub-section of source surface to draw
+ * @param destRect Destination area to draw the surface in. This can be sized differently
+ * then srcRect, allowing for arbitrary scaling of the image
+ * @param transColor Transparency color to ignore copying
+ * @param flipped Specifies whether to horizontally flip the image
+ * @param overrideColor Optional color to use instead of non-transparent pixels from
+ * the source surface
+ */
+ void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect,
+ uint transColor = 0, bool flipped = false, uint overrideColor = 0);
+
+ /**
+ * Clear the entire surface
+ */
+ void clear(uint color = 0);
+
+ /**
+ * Mark the entire surface as dirty
+ */
+ void markAllDirty();
+
+ /**
+ * Copies a bitmap to the Surface internal buffer. The pixel format
+ * of buffer must match the pixel format of the Surface.
+ */
+ void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) {
+ _innerSurface.copyRectToSurface(buffer, srcPitch, destX, destY, width, height);
+ }
+
+ /**
+ * Copies a bitmap to the Surface internal buffer. The pixel format
+ * of buffer must match the pixel format of the Surface.
+ */
+ void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect subRect) {
+ _innerSurface.copyRectToSurface(srcSurface, destX, destY, subRect);
+ }
+
+ /**
+ * Copy the data from another Surface, reinitializing the
+ * surface to match the dimensions of the passed surface
+ */
+ void copyFrom(const ManagedSurface &surf) {
+ clearDirtyRects();
+ _innerSurface.copyFrom(surf._innerSurface);
+ }
+
+ /**
+ * Draw a line.
+ */
+ void drawLine(int x0, int y0, int x1, int y1, uint32 color) {
+ _innerSurface.drawLine(x0, y0, x1, y1, color);
+ addDirtyRect(Common::Rect(x0, y0, x1, y1));
+ }
+
+ /**
+ * Draw a thick line.
+ */
+ void drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY, uint32 color) {
+ _innerSurface.drawThickLine(x0, y0, x1, y1, penX, penY, color);
+ addDirtyRect(Common::Rect(x0, y0, x1 + penX, y1 + penY));
+ }
+
+ /**
+ * Draw a horizontal line.
+ */
+ void hLine(int x, int y, int x2, uint32 color) {
+ _innerSurface.hLine(x, y, x2, color);
+ addDirtyRect(Common::Rect(x, y, x2 + 1, y + 1));
+ }
+
+ /**
+ * Draw a vertical line.
+ */
+ void vLine(int x, int y, int y2, uint32 color) {
+ _innerSurface.vLine(x, y, y2, color);
+ addDirtyRect(Common::Rect(x, y, x + 1, y2 + 1));
+ }
+
+ /**
+ * Fill a rect with a given color.
+ */
+ void fillRect(Common::Rect r, uint32 color) {
+ _innerSurface.fillRect(r, color);
+ addDirtyRect(r);
+ }
+
+ /**
+ * Draw a frame around a specified rect.
+ */
+ void frameRect(const Common::Rect &r, uint32 color) {
+ _innerSurface.frameRect(r, color);
+ addDirtyRect(r);
+ }
+
+ /**
+ * Returns a sub-area of the screen, but only adds a single initial dirty rect
+ * for the retrieved area.
+ */
+ Surface getSubArea(const Common::Rect &area) {
+ addDirtyRect(area);
+ return _innerSurface.getSubArea(area);
+ }
+};
+
+} // End of namespace Graphics
+
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index b6919cf1ab..7331a56c93 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -12,10 +12,13 @@ MODULE_OBJS := \
fonts/ttf.o \
fonts/winfont.o \
maccursor.o \
+ managed_surface.o \
+ nine_patch.o \
pixelformat.o \
primitives.o \
scaler.o \
scaler/thumbnail_intern.o \
+ screen.o \
sjis.o \
surface.o \
transform_struct.o \
diff --git a/graphics/nine_patch.cpp b/graphics/nine_patch.cpp
new file mode 100644
index 0000000000..8ac6977eed
--- /dev/null
+++ b/graphics/nine_patch.cpp
@@ -0,0 +1,279 @@
+/* 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.
+ */
+
+/* This code is based on Nine Patch code by Matthew Leverton
+ taken from https://github.com/konforce/Allegro-Nine-Patch
+
+ Copyright (C) 2011 Matthew Leverton
+
+ 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.
+ */
+
+
+#include "common/array.h"
+#include "graphics/transparent_surface.h"
+#include "graphics/nine_patch.h"
+
+namespace Graphics {
+
+NinePatchSide::~NinePatchSide() {
+ for (uint i = 0; i < _m.size(); i++)
+ delete _m[i];
+
+ _m.clear();
+}
+
+
+bool NinePatchSide::init(Graphics::TransparentSurface *bmp, bool vertical) {
+ const uint len = vertical ? bmp->h : bmp->w;
+ uint i;
+ int s, t, z;
+
+ _m.clear();
+
+ for (i = 1, s = -1, t = 0, z = -1; i < len; ++i) {
+ int zz;
+ uint8 r, g, b, a;
+ uint32 *color = vertical ? (uint32 *)bmp->getBasePtr(0, i) : (uint32 *)bmp->getBasePtr(i, 0);
+ bmp->format.colorToARGB(*color, a, r, g, b);
+
+ if (i == len - 1)
+ zz = -1;
+ else if (r == 0 && g == 0 && b == 0 && a == 255)
+ zz = 0;
+ else if (a == 0 || r + g + b + a == 255 * 4)
+ zz = 1;
+ else
+ return false;
+
+ if (z != zz) {
+ if (s != -1) {
+ NinePatchMark *mrk = new NinePatchMark;
+
+ mrk->offset = s;
+ mrk->length = i - s;
+ if (z == 0) {
+ mrk->ratio = 1;
+ t += mrk->length;
+ } else {
+ mrk->ratio = 0;
+ }
+ _m.push_back(mrk);
+ }
+ s = i;
+ z = zz;
+ }
+ }
+
+ _fix = len - 2 - t;
+ for (i = 0; i < _m.size(); ++i) {
+ if (_m[i]->ratio)
+ _m[i]->ratio = _m[i]->length / (float)t;
+ }
+
+ return true;
+}
+
+void NinePatchSide::calcOffsets(int len) {
+ uint i, j;
+ int dest_offset = 0;
+ int remaining_stretch = len - _fix;
+
+ for (i = 0, j = 0; i < _m.size(); ++i) {
+ _m[i]->dest_offset = dest_offset;
+ if (_m[i]->ratio == 0) {
+ _m[i]->dest_length = _m[i]->length;
+ } else {
+ _m[i]->dest_length = (len - _fix) * _m[i]->ratio;
+ remaining_stretch -= _m[i]->dest_length;
+ j = i;
+ }
+
+ dest_offset += _m[i]->dest_length;
+ }
+
+ if (remaining_stretch) {
+ _m[j]->dest_length += remaining_stretch;
+ if (j + 1 < _m.size())
+ _m[j + 1]->dest_offset += remaining_stretch;
+ }
+}
+
+NinePatchBitmap::NinePatchBitmap(Graphics::TransparentSurface *bmp, bool owns_bitmap) {
+ int i;
+ uint8 r, g, b, a;
+
+ _bmp = bmp;
+ _destroy_bmp = owns_bitmap;
+ _h._m.clear();
+ _v._m.clear();
+ _cached_dw = 0;
+ _cached_dh = 0;
+ _width = bmp->w - 2;
+ _height = bmp->h - 2;
+
+ if (_width <= 0 || _height <= 0)
+ goto bad_bitmap;
+
+ /* make sure all four corners are transparent */
+#define _check_pixel(x, y) \
+ bmp->format.colorToARGB(*(uint32 *)bmp->getBasePtr(x, y), a, r, g, b); \
+ if (a != 0 && r + g + b + a != 4) goto bad_bitmap;
+
+ _check_pixel(0,0);
+ _check_pixel(bmp->w - 1, 0);
+ _check_pixel(0, bmp->h - 1);
+ _check_pixel(bmp->w - 1, bmp->h - 1);
+#undef _check_pixel
+
+ _padding.top = _padding.right = _padding.bottom = _padding.left = -1;
+
+ i = 1;
+ while (i < bmp->w) {
+ bmp->format.colorToARGB(*(uint32 *)bmp->getBasePtr(i, bmp->h - 1), a, r, g, b);
+
+ if (r + g + b == 0 && a == 1) {
+ if (_padding.left == -1)
+ _padding.left = i - 1;
+ else if (_padding.right != -1)
+ goto bad_bitmap;
+ } else if (a == 0 || r + g + b + a == 4) {
+ if (_padding.left != -1 && _padding.right == -1)
+ _padding.right = bmp->w - i - 1;
+ }
+ ++i;
+ }
+
+ i = 1;
+ while (i < bmp->h) {
+ bmp->format.colorToARGB(*(uint32 *)bmp->getBasePtr(bmp->w - 1, i), a, r, g, b);
+
+ if (r + g + b == 0 && a == 1) {
+ if (_padding.top == -1)
+ _padding.top = i - 1;
+ else if (_padding.bottom != -1)
+ goto bad_bitmap;
+ } else if (a == 0 || r + g + b + a == 4) {
+ if (_padding.top != -1 && _padding.bottom == -1)
+ _padding.bottom = bmp->h - i - 1;
+ }
+ ++i;
+ }
+
+ if (!_h.init(bmp, false) || !_v.init(bmp, true)) {
+bad_bitmap:
+ _h._m.clear();
+ _v._m.clear();
+ }
+}
+
+void NinePatchBitmap::blit(Graphics::Surface &target, int dx, int dy, int dw, int dh) {
+ /* don't draw bitmaps that are smaller than the fixed area */
+ if (dw < _h._fix || dh < _v._fix)
+ return;
+
+ /* if the bitmap is the same size as the origin, then draw it as-is */
+ if (dw == _width && dh == _height) {
+ Common::Rect r(1, 1, dw, dh);
+
+ _bmp->blit(target, dx, dy, Graphics::FLIP_NONE, &r);
+ return;
+ }
+
+ /* only recalculate the offsets if they have changed since the last draw */
+ if (_cached_dw != dw || _cached_dh != dh) {
+ _h.calcOffsets(dw);
+ _v.calcOffsets(dh);
+
+ _cached_dw = dw;
+ _cached_dh = dh;
+ }
+
+ /* draw each region */
+ for (uint i = 0; i < _v._m.size(); ++i) {
+ for (uint j = 0; j < _h._m.size(); ++j) {
+ Common::Rect r(_h._m[j]->offset, _v._m[i]->offset,
+ _h._m[j]->offset + _h._m[j]->length, _v._m[i]->offset + _v._m[i]->length);
+
+ _bmp->blit(target, dx + _h._m[j]->dest_offset, dy + _v._m[i]->dest_offset,
+ Graphics::FLIP_NONE, &r, TS_ARGB(255, 255, 255, 255),
+ _h._m[j]->dest_length, _v._m[i]->dest_length);
+ }
+ }
+}
+
+void NinePatchBitmap::blitClip(Graphics::Surface &target, Common::Rect clip, int dx, int dy, int dw, int dh) {
+ /* don't draw bitmaps that are smaller than the fixed area */
+ if (dw < _h._fix || dh < _v._fix)
+ return;
+
+ /* if the bitmap is the same size as the origin, then draw it as-is */
+ if (dw == _width && dh == _height) {
+ Common::Rect r(1, 1, dw, dh);
+
+ _bmp->blitClip(target, clip, dx, dy, Graphics::FLIP_NONE, &r);
+ return;
+ }
+
+ /* only recalculate the offsets if they have changed since the last draw */
+ if (_cached_dw != dw || _cached_dh != dh) {
+ _h.calcOffsets(dw);
+ _v.calcOffsets(dh);
+
+ _cached_dw = dw;
+ _cached_dh = dh;
+ }
+
+ /* draw each region */
+ for (uint i = 0; i < _v._m.size(); ++i) {
+ for (uint j = 0; j < _h._m.size(); ++j) {
+ Common::Rect r(_h._m[j]->offset, _v._m[i]->offset,
+ _h._m[j]->offset + _h._m[j]->length, _v._m[i]->offset + _v._m[i]->length);
+
+ _bmp->blitClip(target, clip, dx + _h._m[j]->dest_offset, dy + _v._m[i]->dest_offset,
+ Graphics::FLIP_NONE, &r, TS_ARGB(255, 255, 255, 255),
+ _h._m[j]->dest_length, _v._m[i]->dest_length);
+ }
+ }
+}
+
+NinePatchBitmap::~NinePatchBitmap() {
+ if (_destroy_bmp)
+ delete _bmp;
+}
+
+} // end of namespace Graphics
diff --git a/graphics/nine_patch.h b/graphics/nine_patch.h
new file mode 100644
index 0000000000..45e4e0918a
--- /dev/null
+++ b/graphics/nine_patch.h
@@ -0,0 +1,98 @@
+/* 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.
+ */
+
+/* This code is based on Nine Patch code by Matthew Leverton
+ taken from https://github.com/konforce/Allegro-Nine-Patch
+
+ Copyright (C) 2011 Matthew Leverton
+
+ 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.
+ */
+
+#ifndef GRAPHICS_NINE_PATCH_H
+#define GRAPHICS_NINE_PATCH_H
+
+#include "common/array.h"
+
+namespace Graphics {
+
+struct NinePatchMark {
+ int offset;
+ int length;
+ int dest_offset;
+ int dest_length;
+ float ratio;
+};
+
+class NinePatchSide {
+public:
+ Common::Array<NinePatchMark *> _m;
+ int _fix;
+
+ NinePatchSide() : _fix(0) {}
+ ~NinePatchSide();
+
+ bool init(Graphics::TransparentSurface *bmp, bool vertical);
+ void calcOffsets(int len);
+};
+
+class NinePatchBitmap {
+ Graphics::TransparentSurface *_bmp;
+ NinePatchSide _h, _v;
+ Common::Rect _padding;
+ bool _destroy_bmp;
+ int _width, _height;
+ int _cached_dw, _cached_dh;
+
+public:
+ NinePatchBitmap(Graphics::TransparentSurface *bmp, bool owns_bitmap);
+ ~NinePatchBitmap();
+
+ void blit(Graphics::Surface &target, int dx, int dy, int dw, int dh);
+ void blitClip(Graphics::Surface &target, Common::Rect clip, int dx, int dy, int dw, int dh);
+
+ int getWidth() { return _width; }
+ int getHeight() { return _height; }
+ int getMinWidth() { return _h._fix; }
+ int getMinHeight() { return _v._fix; }
+ Graphics::TransparentSurface *getSource() { return _bmp; }
+ Common::Rect &getPadding() { return _padding; }
+};
+
+} // end of namespace Graphics
+
+#endif // GRAPHICS_NINE_PATCH_H
diff --git a/graphics/scaler/thumbnail_intern.cpp b/graphics/scaler/thumbnail_intern.cpp
index 65e327f9c2..78fb7828d7 100644
--- a/graphics/scaler/thumbnail_intern.cpp
+++ b/graphics/scaler/thumbnail_intern.cpp
@@ -171,7 +171,8 @@ static bool grabScreen565(Graphics::Surface *surf) {
if (!screen)
return false;
- assert(screen->format.bytesPerPixel == 1 || screen->format.bytesPerPixel == 2);
+ assert(screen->format.bytesPerPixel == 1 || screen->format.bytesPerPixel == 2
+ || screen->format.bytesPerPixel == 4);
assert(screen->getPixels() != 0);
Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
@@ -197,6 +198,9 @@ static bool grabScreen565(Graphics::Surface *surf) {
} else if (screenFormat.bytesPerPixel == 2) {
uint16 col = READ_UINT16(screen->getBasePtr(x, y));
screenFormat.colorToRGB(col, r, g, b);
+ } else if (screenFormat.bytesPerPixel == 4) {
+ uint32 col = READ_UINT32(screen->getBasePtr(x, y));
+ screenFormat.colorToRGB(col, r, g, b);
}
*((uint16 *)surf->getBasePtr(x, y)) = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b);
diff --git a/graphics/screen.cpp b/graphics/screen.cpp
new file mode 100644
index 0000000000..ccf651f536
--- /dev/null
+++ b/graphics/screen.cpp
@@ -0,0 +1,129 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/algorithm.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+
+namespace Graphics {
+
+Screen::Screen(): ManagedSurface() {
+ create(g_system->getWidth(), g_system->getHeight(), g_system->getScreenFormat());
+}
+
+Screen::Screen(int width, int height): ManagedSurface() {
+ create(width, height);
+}
+
+Screen::Screen(int width, int height, PixelFormat pixelFormat): ManagedSurface() {
+ create(width, height, pixelFormat);
+}
+
+void Screen::update() {
+ // Merge the dirty rects
+ mergeDirtyRects();
+
+ // Loop through copying dirty areas to the physical screen
+ Common::List<Common::Rect>::iterator i;
+ for (i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) {
+ const Common::Rect &r = *i;
+ const byte *srcP = (const byte *)getBasePtr(r.left, r.top);
+ g_system->copyRectToScreen(srcP, pitch, r.left, r.top,
+ r.width(), r.height());
+ }
+
+ // Signal the physical screen to update
+ g_system->updateScreen();
+ _dirtyRects.clear();
+}
+
+
+void Screen::addDirtyRect(const Common::Rect &r) {
+ Common::Rect bounds = r;
+ bounds.clip(getBounds());
+ bounds.translate(getOffsetFromOwner().x, getOffsetFromOwner().y);
+
+ if (bounds.width() > 0 && bounds.height() > 0)
+ _dirtyRects.push_back(bounds);
+}
+
+void Screen::makeAllDirty() {
+ addDirtyRect(Common::Rect(0, 0, this->w, this->h));
+}
+
+void Screen::mergeDirtyRects() {
+ Common::List<Common::Rect>::iterator rOuter, rInner;
+
+ // Process the dirty rect list to find any rects to merge
+ for (rOuter = _dirtyRects.begin(); rOuter != _dirtyRects.end(); ++rOuter) {
+ rInner = rOuter;
+ while (++rInner != _dirtyRects.end()) {
+
+ if ((*rOuter).intersects(*rInner)) {
+ // These two rectangles overlap, so merge them
+ unionRectangle(*rOuter, *rOuter, *rInner);
+
+ // remove the inner rect from the list
+ _dirtyRects.erase(rInner);
+
+ // move back to beginning of list
+ rInner = rOuter;
+ }
+ }
+ }
+}
+
+bool Screen::unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2) {
+ destRect = src1;
+ destRect.extend(src2);
+
+ return !destRect.isEmpty();
+}
+
+void Screen::getPalette(byte palette[PALETTE_SIZE]) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->grabPalette(palette, 0, PALETTE_COUNT);
+}
+
+void Screen::getPalette(byte *palette, uint start, uint num) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->grabPalette(palette, start, num);
+}
+
+void Screen::setPalette(const byte palette[PALETTE_SIZE]) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->setPalette(palette, 0, PALETTE_COUNT);
+}
+
+void Screen::setPalette(const byte *palette, uint start, uint num) {
+ assert(format.bytesPerPixel == 1);
+ g_system->getPaletteManager()->setPalette(palette, start, num);
+}
+
+void Screen::clearPalette() {
+ byte palette[PALETTE_SIZE];
+ Common::fill(&palette[0], &palette[PALETTE_SIZE], 0);
+ setPalette(palette);
+}
+
+} // End of namespace Graphics
diff --git a/graphics/screen.h b/graphics/screen.h
new file mode 100644
index 0000000000..b3bb2d3eb2
--- /dev/null
+++ b/graphics/screen.h
@@ -0,0 +1,118 @@
+/* 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.
+ *
+ */
+
+#ifndef GRAPHICS_SCREEN_H
+#define GRAPHICS_SCREEN_H
+
+#include "graphics/managed_surface.h"
+#include "graphics/pixelformat.h"
+#include "common/list.h"
+#include "common/rect.h"
+
+namespace Graphics {
+
+#define PALETTE_COUNT 256
+#define PALETTE_SIZE (256 * 3)
+
+/**
+ * Implements a specialised surface that represents the screen.
+ * It keeps track of any areas of itself that are updated by drawing
+ * calls, and provides an update that method that blits the affected
+ * areas to the physical screen
+ */
+class Screen : public ManagedSurface {
+private:
+ /**
+ * List of affected areas of the screen
+ */
+ Common::List<Common::Rect> _dirtyRects;
+private:
+ /**
+ * Merges together overlapping dirty areas of the screen
+ */
+ void mergeDirtyRects();
+
+ /**
+ * Returns the union of two dirty area rectangles
+ */
+ bool unionRectangle(Common::Rect &destRect, const Common::Rect &src1, const Common::Rect &src2);
+protected:
+ /**
+ * Adds a rectangle to the list of modified areas of the screen during the
+ * current frame
+ */
+ virtual void addDirtyRect(const Common::Rect &r);
+public:
+ Screen();
+ Screen(int width, int height);
+ Screen(int width, int height, PixelFormat pixelFormat);
+
+ /**
+ * Returns true if there are any pending screen updates (dirty areas)
+ */
+ bool isDirty() const { return !_dirtyRects.empty(); }
+
+ /**
+ * Marks the whole screen as dirty. This forces the next call to update
+ * to copy the entire screen contents
+ */
+ void makeAllDirty();
+
+ /**
+ * Clear the current dirty rects list
+ */
+ virtual void clearDirtyRects() { _dirtyRects.clear(); }
+
+ /**
+ * Updates the screen by copying any affected areas to the system
+ */
+ virtual void update();
+
+ /**
+ * Return the currently active palette
+ */
+ void getPalette(byte palette[PALETTE_SIZE]);
+
+ /**
+ * Return a portion of the currently active palette
+ */
+ void getPalette(byte *palette, uint start, uint num);
+
+ /**
+ * Set the palette
+ */
+ void setPalette(const byte palette[PALETTE_SIZE]);
+
+ /**
+ * Set a subsection of the palette
+ */
+ void setPalette(const byte *palette, uint start, uint num);
+
+ /**
+ * Clears the current palette, setting all entries to black
+ */
+ void clearPalette();
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index 67ed942b0b..699e1ccd22 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -498,4 +498,109 @@ Graphics::Surface *Surface::convertTo(const PixelFormat &dstFormat, const byte *
return surface;
}
+FloodFill::FloodFill(Graphics::Surface *surface, uint32 oldColor, uint32 fillColor, bool maskMode) {
+ _surface = surface;
+ _oldColor = oldColor;
+ _fillColor = fillColor;
+ _w = surface->w;
+ _h = surface->h;
+
+ _mask = nullptr;
+ _maskMode = maskMode;
+
+ if (_maskMode) {
+ _mask = new Graphics::Surface();
+ _mask->create(_w, _h, Graphics::PixelFormat::createFormatCLUT8()); // Uses calloc()
+ }
+
+ _visited = (byte *)calloc(_w * _h, 1);
+}
+
+FloodFill::~FloodFill() {
+ while(!_queue.empty()) {
+ Common::Point *p = _queue.front();
+
+ delete p;
+ _queue.pop_front();
+ }
+
+ free(_visited);
+
+ if (_mask)
+ delete _mask;
+}
+
+void FloodFill::addSeed(int x, int y) {
+ if (x >= 0 && x < _w && y >= 0 && y < _h) {
+ if (!_visited[y * _w + x]) {
+ _visited[y * _w + x] = 1;
+ void *src = _surface->getBasePtr(x, y);
+ void *dst;
+ bool changed = false;
+
+ if (_maskMode)
+ dst = _mask->getBasePtr(x, y);
+ else
+ dst = src;
+
+ if (_surface->format.bytesPerPixel == 1) {
+ if (*((byte *)src) == _oldColor) {
+ *((byte *)dst) = _maskMode ? 255 : _fillColor;
+ changed = true;
+ }
+ } else if (_surface->format.bytesPerPixel == 2) {
+ if (READ_UINT16(src) == _oldColor) {
+ if (!_maskMode)
+ WRITE_UINT16(src, _fillColor);
+ else
+ *((byte *)dst) = 255;
+
+ changed = true;
+ }
+ } else if (_surface->format.bytesPerPixel == 4) {
+ if (READ_UINT32(src) == _oldColor) {
+ if (!_maskMode)
+ WRITE_UINT32(src, _fillColor);
+ else
+ *((byte *)dst) = 255;
+
+ changed = true;
+ }
+ } else {
+ error("Unsupported bpp in FloodFill");
+ }
+
+ if (changed) {
+ Common::Point *pt = new Common::Point(x, y);
+
+ _queue.push_back(pt);
+ }
+ }
+ }
+}
+
+void FloodFill::fill() {
+ while (!_queue.empty()) {
+ Common::Point *p = _queue.front();
+ _queue.pop_front();
+ addSeed(p->x , p->y - 1);
+ addSeed(p->x - 1, p->y );
+ addSeed(p->x , p->y + 1);
+ addSeed(p->x + 1, p->y );
+
+ delete p;
+ }
+}
+
+void FloodFill::fillMask() {
+ _maskMode = true;
+
+ if (!_mask) {
+ _mask = new Graphics::Surface();
+ _mask->create(_w, _h, Graphics::PixelFormat::createFormatCLUT8()); // Uses calloc()
+ }
+
+ fill();
+}
+
} // End of namespace Graphics
diff --git a/graphics/surface.h b/graphics/surface.h
index aaa386b168..87c5f52503 100644
--- a/graphics/surface.h
+++ b/graphics/surface.h
@@ -24,9 +24,11 @@
#define GRAPHICS_SURFACE_H
#include "common/scummsys.h"
+#include "common/list.h"
namespace Common {
struct Rect;
+struct Point;
}
#include "graphics/pixelformat.h"
@@ -341,6 +343,72 @@ struct SharedPtrSurfaceDeleter {
}
};
+/**
+ * Stack-based flood fill algorithm for arbitrary Surfaces.
+ *
+ * It could be used in 2 ways. One is to fill the pixels of oldColor
+ * with fillColor. Second is when the surface stays intact but another
+ * surface with mask is created, where filled colors are marked with 255.
+ *
+ * Before running fill() or fillMask(), the initial pixels must be addSeed
+ * with addSeed() method.
+ */
+class FloodFill {
+public:
+ /**
+ * Construct a simple Surface object.
+ *
+ * @param surface Input surface
+ * @param oldColor Color on the surface to change
+ * @param fillColor Color to fill with
+ */
+ FloodFill(Surface *surface, uint32 oldColor, uint32 fillColor, bool maskMode = false);
+ ~FloodFill();
+
+ /**
+ * Add pixels to the fill queue.
+ *
+ * @param x The x coordinate of the pixel.
+ * @param y The x coordinate of the pixel.
+ */
+ void addSeed(int x, int y);
+
+ /**
+ * Fill the surface as requested.
+ *
+ * It uses pixels which were added with addSeed() method.
+ *
+ * @see addSeed
+ */
+ void fill();
+
+ /**
+ * Fill the mask. The mask is a CLUT8 Surface with pixels 0 and 255.
+ * 255 means that the pixel has been filled.
+ *
+ * It uses pixels which were added with addSeed() method.
+ *
+ * @see addSeed
+ */
+ void fillMask();
+
+ /**
+ * Get the resulting mask.
+ *
+ * @see fillMask
+ */
+ Surface *getMask() { return _mask; }
+
+private:
+ Common::List<Common::Point *> _queue;
+ Surface *_surface;
+ Surface *_mask;
+ uint32 _oldColor, _fillColor;
+ byte *_visited;
+ int _w, _h;
+
+ bool _maskMode;
+};
} // End of namespace Graphics
diff --git a/graphics/transparent_surface.cpp b/graphics/transparent_surface.cpp
index 19e7655a93..c2903d42c3 100644
--- a/graphics/transparent_surface.cpp
+++ b/graphics/transparent_surface.cpp
@@ -462,6 +462,139 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p
return retSize;
}
+Common::Rect TransparentSurface::blitClip(Graphics::Surface &target, Common::Rect clippingArea, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {
+ Common::Rect retSize;
+ retSize.top = 0;
+ retSize.left = 0;
+ retSize.setWidth(0);
+ retSize.setHeight(0);
+ // Check if we need to draw anything at all
+ int ca = (color >> kAModShift) & 0xff;
+
+ if (ca == 0) {
+ return retSize;
+ }
+
+ // Create an encapsulating surface for the data
+ TransparentSurface srcImage(*this, false);
+ // TODO: Is the data really in the screen format?
+ if (format.bytesPerPixel != 4) {
+ warning("TransparentSurface can only blit 32bpp images, but got %d", format.bytesPerPixel * 8);
+ return retSize;
+ }
+
+ if (pPartRect) {
+
+ int xOffset = pPartRect->left;
+ int yOffset = pPartRect->top;
+
+ if (flipping & FLIP_V) {
+ yOffset = srcImage.h - pPartRect->bottom;
+ }
+
+ if (flipping & FLIP_H) {
+ xOffset = srcImage.w - pPartRect->right;
+ }
+
+ srcImage.pixels = getBasePtr(xOffset, yOffset);
+ srcImage.w = pPartRect->width();
+ srcImage.h = pPartRect->height();
+
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
+ pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
+ } else {
+
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
+ srcImage.w, srcImage.h, color, width, height);
+ }
+
+ if (width == -1) {
+ width = srcImage.w;
+ }
+ if (height == -1) {
+ height = srcImage.h;
+ }
+
+#ifdef SCALING_TESTING
+ // Hardcode scaling to 66% to test scaling
+ width = width * 2 / 3;
+ height = height * 2 / 3;
+#endif
+
+ Graphics::Surface *img = nullptr;
+ Graphics::Surface *imgScaled = nullptr;
+ byte *savedPixels = nullptr;
+ if ((width != srcImage.w) || (height != srcImage.h)) {
+ // Scale the image
+ img = imgScaled = srcImage.scale(width, height);
+ savedPixels = (byte *)img->getPixels();
+ } else {
+ img = &srcImage;
+ }
+
+ // Handle off-screen clipping
+ if (posY < clippingArea.top) {
+ img->h = MAX(0, (int)img->h - (clippingArea.top - posY));
+ img->setPixels((byte *)img->getBasePtr(0, clippingArea.top - posY));
+ posY = clippingArea.top;
+ }
+
+ if (posX < clippingArea.left) {
+ img->w = MAX(0, (int)img->w - (clippingArea.left - posX));
+ img->setPixels((byte *)img->getBasePtr(clippingArea.left - posX, 0));
+ posX = clippingArea.left;
+ }
+
+ img->w = CLIP((int)img->w, 0, (int)MAX((int)clippingArea.right - posX, 0));
+ img->h = CLIP((int)img->h, 0, (int)MAX((int)clippingArea.bottom - posY, 0));
+
+ if ((img->w > 0) && (img->h > 0)) {
+ int xp = 0, yp = 0;
+
+ int inStep = 4;
+ int inoStep = img->pitch;
+ if (flipping & FLIP_H) {
+ inStep = -inStep;
+ xp = img->w - 1;
+ }
+
+ if (flipping & FLIP_V) {
+ inoStep = -inoStep;
+ yp = img->h - 1;
+ }
+
+ byte *ino = (byte *)img->getBasePtr(xp, yp);
+ byte *outo = (byte *)target.getBasePtr(posX, posY);
+
+ if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) {
+ doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
+ } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) {
+ doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
+ } else {
+ if (blendMode == BLEND_ADDITIVE) {
+ doBlitAdditiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
+ } else if (blendMode == BLEND_SUBTRACTIVE) {
+ doBlitSubtractiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
+ } else {
+ assert(blendMode == BLEND_NORMAL);
+ doBlitAlphaBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
+ }
+ }
+
+ }
+
+ retSize.setWidth(img->w);
+ retSize.setHeight(img->h);
+
+ if (imgScaled) {
+ imgScaled->setPixels(savedPixels);
+ imgScaled->free();
+ delete imgScaled;
+ }
+
+ return retSize;
+}
+
/**
* Writes a color key to the alpha channel of the surface
* @param rKey the red component of the color key
diff --git a/graphics/transparent_surface.h b/graphics/transparent_surface.h
index 0cd7d5b2e9..c0d3d26e52 100644
--- a/graphics/transparent_surface.h
+++ b/graphics/transparent_surface.h
@@ -123,6 +123,14 @@ struct TransparentSurface : public Graphics::Surface {
uint color = TS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
TSpriteBlendMode blend = BLEND_NORMAL);
+ Common::Rect blitClip(Graphics::Surface &target, Common::Rect clippingArea,
+ int posX = 0, int posY = 0,
+ int flipping = FLIP_NONE,
+ Common::Rect *pPartRect = nullptr,
+ uint color = TS_ARGB(255, 255, 255, 255),
+ int width = -1, int height = -1,
+ TSpriteBlendMode blend = BLEND_NORMAL);
+
void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false);
/**
diff --git a/gui/EventRecorder.cpp b/gui/EventRecorder.cpp
index d0371f5e78..3f91cfa259 100644
--- a/gui/EventRecorder.cpp
+++ b/gui/EventRecorder.cpp
@@ -330,7 +330,7 @@ bool EventRecorder::openRecordFile(const Common::String &fileName) {
}
bool EventRecorder::checkGameHash(const ADGameDescription *gameDesc) {
- if (_playbackFile->getHeader().hashRecords.size() != 0) {
+ if (_playbackFile->getHeader().hashRecords.size() == 0) {
warning("Engine doesn't contain description table");
return false;
}
@@ -676,4 +676,3 @@ void EventRecorder::deleteTemporarySave() {
} // End of namespace GUI
#endif // ENABLE_EVENTRECORDER
-
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index 1b95a11e03..c850a6a02e 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -121,6 +121,19 @@ protected:
const WidgetDrawData *_data;
};
+class ThemeItemDrawDataClip: public ThemeItem{
+public:
+ ThemeItemDrawDataClip(ThemeEngine *engine, const WidgetDrawData *data, const Common::Rect &area, const Common::Rect &clip, uint32 dynData) :
+ ThemeItem(engine, area), _dynamicData(dynData), _data(data), _clip(clip) {}
+
+ void drawSelf(bool draw, bool restore);
+
+protected:
+ uint32 _dynamicData;
+ const WidgetDrawData *_data;
+ const Common::Rect _clip;
+};
+
class ThemeItemTextData : public ThemeItem {
public:
ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const TextColorData *color, const Common::Rect &area, const Common::Rect &textDrawableArea,
@@ -155,7 +168,18 @@ protected:
bool _alpha;
};
+class ThemeItemBitmapClip : public ThemeItem {
+public:
+ ThemeItemBitmapClip(ThemeEngine *engine, const Common::Rect &area, const Common::Rect &clip, const Graphics::Surface *bitmap, bool alpha) :
+ ThemeItem(engine, area), _bitmap(bitmap), _alpha(alpha), _clip(clip) {}
+
+ void drawSelf(bool draw, bool restore);
+protected:
+ const Graphics::Surface *_bitmap;
+ bool _alpha;
+ const Common::Rect _clip;
+};
/**********************************************************
* Data definitions for theme engine elements
@@ -164,7 +188,7 @@ struct DrawDataInfo {
DrawData id; ///< The actual ID of the DrawData item.
const char *name; ///< The name of the DrawData item as it appears in the Theme Description files
bool buffer; ///< Sets whether this item is buffered on the backbuffer or drawn directly to the screen.
- DrawData parent; ///< Parent DrawData item, for items that overlay. E.g. kButtonIdle -> kButtonHover
+ DrawData parent; ///< Parent DrawData item, for items that overlay. E.g. kDDButtonIdle -> kDDButtonHover
};
/**
@@ -242,16 +266,40 @@ void ThemeItemDrawData::drawSelf(bool draw, bool restore) {
_engine->addDirtyRect(extendedRect);
}
+void ThemeItemDrawDataClip::drawSelf(bool draw, bool restore) {
+
+ Common::Rect extendedRect = _area;
+ extendedRect.grow(_engine->kDirtyRectangleThreshold + _data->_backgroundOffset);
+
+ if (restore)
+ _engine->restoreBackground(extendedRect);
+
+ if (draw) {
+ Common::List<Graphics::DrawStep>::const_iterator step;
+ for (step = _data->_steps.begin(); step != _data->_steps.end(); ++step) {
+ _engine->renderer()->drawStepClip(_area, _clip, *step, _dynamicData);
+ }
+ }
+
+ extendedRect.clip(_clip);
+
+ _engine->addDirtyRect(extendedRect);
+}
+
void ThemeItemTextData::drawSelf(bool draw, bool restore) {
+ Common::Rect dirty = _textDrawableArea;
+ if (dirty.isEmpty()) dirty = _area;
+ else dirty.clip(_area);
+
if (_restoreBg || restore)
- _engine->restoreBackground(_area);
+ _engine->restoreBackground(dirty);
if (draw) {
_engine->renderer()->setFgColor(_color->r, _color->g, _color->b);
_engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis, _textDrawableArea);
}
- _engine->addDirtyRect(_area);
+ _engine->addDirtyRect(dirty);
}
void ThemeItemBitmap::drawSelf(bool draw, bool restore) {
@@ -268,7 +316,21 @@ void ThemeItemBitmap::drawSelf(bool draw, bool restore) {
_engine->addDirtyRect(_area);
}
+void ThemeItemBitmapClip::drawSelf(bool draw, bool restore) {
+ if (restore)
+ _engine->restoreBackground(_area);
+ if (draw) {
+ if (_alpha)
+ _engine->renderer()->blitAlphaBitmapClip(_bitmap, _area, _clip);
+ else
+ _engine->renderer()->blitSubSurfaceClip(_bitmap, _area, _clip);
+ }
+
+ Common::Rect dirtyRect = _area;
+ dirtyRect.clip(_clip);
+ _engine->addDirtyRect(dirtyRect);
+}
/**********************************************************
* ThemeEngine class
@@ -311,6 +373,12 @@ ThemeEngine::ThemeEngine(Common::String id, GraphicsMode mode) :
_themeArchive = 0;
_initOk = false;
+ _cursorHotspotX = _cursorHotspotY = 0;
+ _cursorWidth = _cursorHeight = 0;
+ _cursorPalSize = 0;
+
+ _needPaletteUpdates = false;
+
// We prefer files in archive bundles over the common search paths.
_themeFiles.add("default", &SearchMan, 0, false);
}
@@ -558,7 +626,7 @@ void ThemeEngine::restoreBackground(Common::Rect r) {
void ThemeEngine::addDrawStep(const Common::String &drawDataId, const Graphics::DrawStep &step) {
DrawData id = parseDrawDataId(drawDataId);
- assert(_widgets[id] != 0);
+ assert(id != kDDNone && _widgets[id] != 0);
_widgets[id]->_steps.push_back(step);
}
@@ -856,10 +924,34 @@ void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic,
}
}
+void ThemeEngine::queueDDClip(DrawData type, const Common::Rect &r, const Common::Rect &clippingRect, uint32 dynamic, bool restore) {
+ if (_widgets[type] == 0)
+ return;
+
+ Common::Rect area = r;
+ area.clip(_screen.w, _screen.h);
+
+ ThemeItemDrawDataClip *q = new ThemeItemDrawDataClip(this, _widgets[type], area, clippingRect, dynamic);
+
+ if (_buffering) {
+ if (_widgets[type]->_buffer) {
+ _bufferQueue.push_back(q);
+ } else {
+ if (kDrawDataDefaults[type].parent != kDDNone && kDrawDataDefaults[type].parent != type)
+ queueDDClip(kDrawDataDefaults[type].parent, r, clippingRect);
+
+ _screenQueue.push_back(q);
+ }
+ } else {
+ q->drawSelf(!_widgets[type]->_buffer, restore || _widgets[type]->_buffer);
+ delete q;
+ }
+}
+
void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg,
bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax, const Common::Rect &drawableTextArea) {
- if (_texts[type] == 0)
+ if (type == kTextDataNone || _texts[type] == 0)
return;
Common::Rect area = r;
@@ -875,6 +967,28 @@ void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect
}
}
+void ThemeEngine::queueDDTextClip(TextData type, TextColor color, const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &text, bool restoreBg,
+ bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax, const Common::Rect &drawableTextArea) {
+
+ if (_texts[type] == 0)
+ return;
+
+ Common::Rect area = r;
+ area.clip(_screen.w, _screen.h);
+ Common::Rect textArea = drawableTextArea;
+ if (textArea.isEmpty()) textArea = clippingArea;
+ else textArea.clip(clippingArea);
+
+ ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, textArea, text, alignH, alignV, ellipsis, restoreBg, deltax);
+
+ if (_buffering) {
+ _screenQueue.push_back(q);
+ } else {
+ q->drawSelf(true, false);
+ delete q;
+ }
+}
+
void ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha) {
Common::Rect area = r;
@@ -890,7 +1004,20 @@ void ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rec
}
}
+void ThemeEngine::queueBitmapClip(const Graphics::Surface *bitmap, const Common::Rect &r, const Common::Rect &clip, bool alpha) {
+
+ Common::Rect area = r;
+ area.clip(_screen.w, _screen.h);
+
+ ThemeItemBitmapClip *q = new ThemeItemBitmapClip(this, area, clip, bitmap, alpha);
+ if (_buffering) {
+ _screenQueue.push_back(q);
+ } else {
+ q->drawSelf(true, false);
+ delete q;
+ }
+}
/**********************************************************
* Widget drawing functions
@@ -914,6 +1041,25 @@ void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, W
queueDDText(getTextData(dd), getTextColor(dd), r, str, false, true, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV);
}
+void ThemeEngine::drawButtonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, WidgetStateInfo state, uint16 hints) {
+ if (!ready())
+ return;
+
+ DrawData dd = kDDButtonIdle;
+
+ if (state == kStateEnabled)
+ dd = kDDButtonIdle;
+ else if (state == kStateHighlight)
+ dd = kDDButtonHover;
+ else if (state == kStateDisabled)
+ dd = kDDButtonDisabled;
+ else if (state == kStatePressed)
+ dd = kDDButtonPressed;
+
+ queueDDClip(dd, r, clippingRect, 0, hints & WIDGET_CLEARBG);
+ queueDDTextClip(getTextData(dd), getTextColor(dd), r, clippingRect, str, false, true, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV);
+}
+
void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) {
if (!ready())
return;
@@ -921,6 +1067,13 @@ void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state
queueDD(kDDSeparator, r);
}
+void ThemeEngine::drawLineSeparatorClip(const Common::Rect &r, const Common::Rect &clippingRect, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ queueDDClip(kDDSeparator, r, clippingRect);
+}
+
void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
if (!ready())
return;
@@ -947,6 +1100,32 @@ void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str,
queueDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV);
}
+void ThemeEngine::drawCheckboxClip(const Common::Rect &r, const Common::Rect &clip, const Common::String &str, bool checked, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ Common::Rect r2 = r;
+ DrawData dd = kDDCheckboxDefault;
+
+ if (checked)
+ dd = kDDCheckboxSelected;
+
+ if (state == kStateDisabled)
+ dd = kDDCheckboxDisabled;
+
+ const int checkBoxSize = MIN((int)r.height(), getFontHeight());
+
+ r2.bottom = r2.top + checkBoxSize;
+ r2.right = r2.left + checkBoxSize;
+
+ queueDDClip(dd, r2, clip);
+
+ r2.left = r2.right + checkBoxSize;
+ r2.right = r.right;
+
+ queueDDTextClip(getTextData(dd), getTextColor(dd), r2, clip, str, true, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV);
+}
+
void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) {
if (!ready())
return;
@@ -973,6 +1152,32 @@ void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &s
queueDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDRadiobuttonDefault]->_textAlignH, _widgets[dd]->_textAlignV);
}
+void ThemeEngine::drawRadiobuttonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, bool checked, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ Common::Rect r2 = r;
+ DrawData dd = kDDRadiobuttonDefault;
+
+ if (checked)
+ dd = kDDRadiobuttonSelected;
+
+ if (state == kStateDisabled)
+ dd = kDDRadiobuttonDisabled;
+
+ const int checkBoxSize = MIN((int)r.height(), getFontHeight());
+
+ r2.bottom = r2.top + checkBoxSize;
+ r2.right = r2.left + checkBoxSize;
+
+ queueDDClip(dd, r2, clippingRect);
+
+ r2.left = r2.right + checkBoxSize;
+ r2.right = r.right;
+
+ queueDDTextClip(getTextData(dd), getTextColor(dd), r2, clippingRect, str, true, false, _widgets[kDDRadiobuttonDefault]->_textAlignH, _widgets[dd]->_textAlignV);
+}
+
void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) {
if (!ready())
return;
@@ -993,6 +1198,26 @@ void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo s
queueDD(dd, r2);
}
+void ThemeEngine::drawSliderClip(const Common::Rect &r, const Common::Rect &clip, int width, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ DrawData dd = kDDSliderFull;
+
+ if (state == kStateHighlight)
+ dd = kDDSliderHover;
+ else if (state == kStateDisabled)
+ dd = kDDSliderDisabled;
+
+ Common::Rect r2 = r;
+ r2.setWidth(MIN((int16)width, r.width()));
+ // r2.top++; r2.bottom--; r2.left++; r2.right--;
+
+ drawWidgetBackgroundClip(r, clip, 0, kWidgetBackgroundSlider, kStateEnabled);
+
+ queueDDClip(dd, r2, clip);
+}
+
void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) {
if (!ready())
return;
@@ -1014,11 +1239,34 @@ void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHe
r2.top += sliderY;
r2.bottom = r2.top + sliderHeight;
- r2.top += r.width() / 5;
- r2.bottom -= r.width() / 5;
+ //r2.top += r.width() / 5;
+ //r2.bottom -= r.width() / 5;
queueDD(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2);
}
+void ThemeEngine::drawScrollbarClip(const Common::Rect &r, const Common::Rect &clippingRect, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ queueDDClip(kDDScrollbarBase, r, clippingRect);
+
+ Common::Rect r2 = r;
+ const int buttonExtra = (r.width() * 120) / 100;
+
+ r2.bottom = r2.top + buttonExtra;
+ queueDDClip(scrollState == kScrollbarStateUp ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, clippingRect, Graphics::VectorRenderer::kTriangleUp);
+
+ r2.translate(0, r.height() - r2.height());
+ queueDDClip(scrollState == kScrollbarStateDown ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, clippingRect, Graphics::VectorRenderer::kTriangleDown);
+
+ r2 = r;
+ r2.left += 1;
+ r2.right -= 1;
+ r2.top += sliderY;
+ r2.bottom = r2.top + sliderHeight;
+ queueDDClip(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2, clippingRect);
+}
+
void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground bgtype, WidgetStateInfo state) {
if (!ready())
return;
@@ -1046,6 +1294,33 @@ void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground b
}
}
+void ThemeEngine::drawDialogBackgroundClip(const Common::Rect &r, const Common::Rect &clip, DialogBackground bgtype, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ switch (bgtype) {
+ case kDialogBackgroundMain:
+ queueDDClip(kDDMainDialogBackground, r, clip);
+ break;
+
+ case kDialogBackgroundSpecial:
+ queueDDClip(kDDSpecialColorBackground, r, clip);
+ break;
+
+ case kDialogBackgroundPlain:
+ queueDDClip(kDDPlainColorBackground, r, clip);
+ break;
+
+ case kDialogBackgroundTooltip:
+ queueDDClip(kDDTooltipBackground, r, clip);
+ break;
+
+ case kDialogBackgroundDefault:
+ queueDDClip(kDDDefaultBackground, r, clip);
+ break;
+ }
+}
+
void ThemeEngine::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) {
if (!ready())
return;
@@ -1057,6 +1332,17 @@ void ThemeEngine::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo s
queueDD(kDDCaret, r);
}
+void ThemeEngine::drawCaretClip(const Common::Rect &r, const Common::Rect &clip, bool erase, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ if (erase) {
+ restoreBackground(r);
+ addDirtyRect(r);
+ } else
+ queueDDClip(kDDCaret, r, clip);
+}
+
void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, Graphics::TextAlign align) {
if (!ready())
return;
@@ -1078,6 +1364,27 @@ void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &s
}
}
+void ThemeEngine::drawPopUpWidgetClip(const Common::Rect &r, const Common::Rect &clip, const Common::String &sel, int deltax, WidgetStateInfo state, Graphics::TextAlign align) {
+ if (!ready())
+ return;
+
+ DrawData dd = kDDPopUpIdle;
+
+ if (state == kStateEnabled)
+ dd = kDDPopUpIdle;
+ else if (state == kStateHighlight)
+ dd = kDDPopUpHover;
+ else if (state == kStateDisabled)
+ dd = kDDPopUpDisabled;
+
+ queueDDClip(dd, r, clip);
+
+ if (!sel.empty()) {
+ Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom);
+ queueDDTextClip(getTextData(dd), getTextColor(dd), text, clip, sel, true, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV, deltax);
+ }
+}
+
void ThemeEngine::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) {
if (!ready())
return;
@@ -1085,6 +1392,13 @@ void ThemeEngine::drawSurface(const Common::Rect &r, const Graphics::Surface &su
queueBitmap(&surface, r, themeTrans);
}
+void ThemeEngine::drawSurfaceClip(const Common::Rect &r, const Common::Rect &clip, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) {
+ if (!ready())
+ return;
+
+ queueBitmapClip(&surface, r, clip, themeTrans);
+}
+
void ThemeEngine::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) {
if (!ready())
return;
@@ -1108,6 +1422,29 @@ void ThemeEngine::drawWidgetBackground(const Common::Rect &r, uint16 hints, Widg
}
}
+void ThemeEngine::drawWidgetBackgroundClip(const Common::Rect &r, const Common::Rect &clip, uint16 hints, WidgetBackground background, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ switch (background) {
+ case kWidgetBackgroundBorderSmall:
+ queueDDClip(kDDWidgetBackgroundSmall, r, clip);
+ break;
+
+ case kWidgetBackgroundEditText:
+ queueDDClip(kDDWidgetBackgroundEditText, r, clip);
+ break;
+
+ case kWidgetBackgroundSlider:
+ queueDDClip(kDDWidgetBackgroundSlider, r, clip);
+ break;
+
+ default:
+ queueDDClip(kDDWidgetBackgroundDefault, r, clip);
+ break;
+ }
+}
+
void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
if (!ready())
return;
@@ -1136,6 +1473,34 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, co
}
}
+void ThemeEngine::drawTabClip(const Common::Rect &r, const Common::Rect &clip, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
+ if (!ready())
+ return;
+
+ queueDDClip(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight), clip);
+
+ for (int i = 0; i < (int)tabs.size(); ++i) {
+ if (i == active)
+ continue;
+
+ if (r.left + i * tabWidth > r.right || r.left + (i + 1) * tabWidth > r.right)
+ continue;
+
+ Common::Rect tabRect(r.left + i * tabWidth, r.top, r.left + (i + 1) * tabWidth, r.top + tabHeight);
+ queueDDClip(kDDTabInactive, tabRect, clip);
+ queueDDTextClip(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, clip, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV);
+ }
+
+ if (active >= 0 &&
+ (r.left + active * tabWidth < r.right) && (r.left + (active + 1) * tabWidth < r.right)) {
+ Common::Rect tabRect(r.left + active * tabWidth, r.top, r.left + (active + 1) * tabWidth, r.top + tabHeight);
+ const uint16 tabLeft = active * tabWidth;
+ const uint16 tabRight = MAX(r.right - tabRect.right, 0);
+ queueDDClip(kDDTabActive, tabRect, clip, (tabLeft << 16) | (tabRight & 0xFFFF));
+ queueDDTextClip(getTextData(kDDTabActive), getTextColor(kDDTabActive), tabRect, clip, tabs[active], false, false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV);
+ }
+}
+
void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore, const Common::Rect &drawableTextArea) {
if (!ready())
return;
@@ -1209,6 +1574,79 @@ void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, Wid
queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax, drawableTextArea);
}
+void ThemeEngine::drawTextClip(const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore, const Common::Rect &drawableTextArea) {
+ if (!ready())
+ return;
+
+ TextColor colorId = kTextColorMAX;
+
+ switch (color) {
+ case kFontColorNormal:
+ if (inverted) {
+ colorId = kTextColorNormalInverted;
+ } else {
+ switch (state) {
+ case kStateDisabled:
+ colorId = kTextColorNormalDisabled;
+ break;
+
+ case kStateHighlight:
+ colorId = kTextColorNormalHover;
+ break;
+
+ case kStateEnabled:
+ case kStatePressed:
+ colorId = kTextColorNormal;
+ break;
+ }
+ }
+ break;
+
+ case kFontColorAlternate:
+ if (inverted) {
+ colorId = kTextColorAlternativeInverted;
+ } else {
+ switch (state) {
+ case kStateDisabled:
+ colorId = kTextColorAlternativeDisabled;
+ break;
+
+ case kStateHighlight:
+ colorId = kTextColorAlternativeHover;
+ break;
+
+ case kStateEnabled:
+ case kStatePressed:
+ colorId = kTextColorAlternative;
+ break;
+ }
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ TextData textId = fontStyleToData(font);
+
+ switch (inverted) {
+ case kTextInversion:
+ queueDDClip(kDDTextSelectionBackground, r, clippingArea);
+ restore = false;
+ break;
+
+ case kTextInversionFocus:
+ queueDDClip(kDDTextSelectionFocusBackground, r, clippingArea);
+ restore = false;
+ break;
+
+ default:
+ break;
+ }
+
+ queueDDTextClip(textId, colorId, r, clippingArea, str, restore, useEllipsis, align, kTextAlignVCenter, deltax, drawableTextArea);
+}
+
void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) {
if (!ready())
return;
@@ -1223,6 +1661,21 @@ void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font
addDirtyRect(charArea);
}
+void ThemeEngine::drawCharClip(const Common::Rect &r, const Common::Rect &clip, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) {
+ if (!ready())
+ return;
+
+ Common::Rect charArea = r;
+ charArea.clip(_screen.w, _screen.h);
+ if (!clip.isEmpty()) charArea.clip(clip);
+
+ uint32 rgbColor = _overlayFormat.RGBToColor(_textColors[color]->r, _textColors[color]->g, _textColors[color]->b);
+
+ restoreBackground(charArea);
+ font->drawChar(&_screen, ch, charArea.left, charArea.top, rgbColor);
+ addDirtyRect(charArea);
+}
+
void ThemeEngine::debugWidgetPosition(const char *name, const Common::Rect &r) {
_font->drawString(&_screen, name, r.left, r.top, r.width(), 0xFFFF, Graphics::kTextAlignRight, 0, true);
_screen.hLine(r.left, r.top, r.right, 0xFFFF);
@@ -1259,8 +1712,15 @@ void ThemeEngine::updateScreen(bool render) {
_screenQueue.clear();
}
- if (render)
+ if (render) {
+#ifdef LAYOUT_DEBUG_DIALOG
+ _vectorRenderer->fillSurface();
+ _themeEval->debugDraw(&_screen, _font);
+ _vectorRenderer->copyWholeFrame(_system);
+#else
renderDirtyScreen();
+#endif
+ }
}
void ThemeEngine::addDirtyRect(Common::Rect r) {
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index a5ef49c78b..3c259b4f9d 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -340,42 +340,67 @@ public:
void drawWidgetBackground(const Common::Rect &r, uint16 hints,
WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled);
+ void drawWidgetBackgroundClip(const Common::Rect &r, const Common::Rect &clippingArea, uint16 hints,
+ WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled);
void drawButton(const Common::Rect &r, const Common::String &str,
WidgetStateInfo state = kStateEnabled, uint16 hints = 0);
+ void drawButtonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str,
+ WidgetStateInfo state = kStateEnabled, uint16 hints = 0);
void drawSurface(const Common::Rect &r, const Graphics::Surface &surface,
- WidgetStateInfo state = kStateEnabled, int alpha = 256, bool themeTrans = false);
+ WidgetStateInfo state = kStateEnabled, int alpha = 255, bool themeTrans = false);
+ void drawSurfaceClip(const Common::Rect &r, const Common::Rect &clippingRect, const Graphics::Surface &surface,
+ WidgetStateInfo state = kStateEnabled, int alpha = 255, bool themeTrans = false);
void drawSlider(const Common::Rect &r, int width,
WidgetStateInfo state = kStateEnabled);
+ void drawSliderClip(const Common::Rect &r, const Common::Rect &clippingRect, int width,
+ WidgetStateInfo state = kStateEnabled);
void drawCheckbox(const Common::Rect &r, const Common::String &str,
bool checked, WidgetStateInfo state = kStateEnabled);
+ void drawCheckboxClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str,
+ bool checked, WidgetStateInfo state = kStateEnabled);
void drawRadiobutton(const Common::Rect &r, const Common::String &str,
bool checked, WidgetStateInfo state = kStateEnabled);
+ void drawRadiobuttonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str,
+ bool checked, WidgetStateInfo state = kStateEnabled);
void drawTab(const Common::Rect &r, int tabHeight, int tabWidth,
const Common::Array<Common::String> &tabs, int active, uint16 hints,
int titleVPad, WidgetStateInfo state = kStateEnabled);
+ void drawTabClip(const Common::Rect &r, const Common::Rect &clippingRect, int tabHeight, int tabWidth,
+ const Common::Array<Common::String> &tabs, int active, uint16 hints,
+ int titleVPad, WidgetStateInfo state = kStateEnabled);
void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight,
ScrollbarState, WidgetStateInfo state = kStateEnabled);
+ void drawScrollbarClip(const Common::Rect &r, const Common::Rect &clippingRect, int sliderY, int sliderHeight,
+ ScrollbarState scrollState, WidgetStateInfo state = kStateEnabled);
void drawPopUpWidget(const Common::Rect &r, const Common::String &sel,
int deltax, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignLeft);
+ void drawPopUpWidgetClip(const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &sel,
+ int deltax, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignLeft);
void drawCaret(const Common::Rect &r, bool erase,
WidgetStateInfo state = kStateEnabled);
+ void drawCaretClip(const Common::Rect &r, const Common::Rect &clip, bool erase,
+ WidgetStateInfo state = kStateEnabled);
void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled);
+ void drawLineSeparatorClip(const Common::Rect &r, const Common::Rect &clippingArea, WidgetStateInfo state = kStateEnabled);
void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled);
+ void drawDialogBackgroundClip(const Common::Rect &r, const Common::Rect &clip, DialogBackground type, WidgetStateInfo state = kStateEnabled);
void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal, bool restore = true, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0));
+ void drawTextClip(const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal, bool restore = true, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0));
void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled, FontColor color = kFontColorNormal);
+ void drawCharClip(const Common::Rect &r, const Common::Rect &clippingArea, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled, FontColor color = kFontColorNormal);
//@}
@@ -584,9 +609,13 @@ protected:
* This function is called from all the Widget Drawing methods.
*/
void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0, bool restore = false);
+ void queueDDClip(DrawData type, const Common::Rect &r, const Common::Rect &clippingRect, uint32 dynamic = 0, bool restore = false);
void queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg,
bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0));
+ void queueDDTextClip(TextData type, TextColor color, const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &text, bool restoreBg,
+ bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0));
void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha);
+ void queueBitmapClip(const Graphics::Surface *bitmap, const Common::Rect &clippingRect, const Common::Rect &r, bool alpha);
/**
* DEBUG: Draws a white square and writes some text next to it.
diff --git a/gui/ThemeEval.cpp b/gui/ThemeEval.cpp
index 9d57d2408b..5255587089 100644
--- a/gui/ThemeEval.cpp
+++ b/gui/ThemeEval.cpp
@@ -91,10 +91,18 @@ void ThemeEval::addWidget(const Common::String &name, int w, int h, const Common
typeAlign = (Graphics::TextAlign)getVar("Globals." + type + ".Align", Graphics::kTextAlignInvalid);
}
- ThemeLayoutWidget *widget = new ThemeLayoutWidget(_curLayout.top(), name,
- typeW == -1 ? w : typeW,
- typeH == -1 ? h : typeH,
- typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign);
+ ThemeLayoutWidget *widget;
+ if (type == "TabWidget")
+ widget = new ThemeLayoutTabWidget(_curLayout.top(), name,
+ typeW == -1 ? w : typeW,
+ typeH == -1 ? h : typeH,
+ typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign,
+ getVar("Globals.TabWidget.Tab.Height", 0));
+ else
+ widget = new ThemeLayoutWidget(_curLayout.top(), name,
+ typeW == -1 ? w : typeW,
+ typeH == -1 ? h : typeH,
+ typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign);
_curLayout.top()->addChild(widget);
setVar(_curDialog + "." + name + ".Enabled", enabled ? 1 : 0);
diff --git a/gui/ThemeLayout.cpp b/gui/ThemeLayout.cpp
index 6a6fd9e343..71e4b2c9fd 100644
--- a/gui/ThemeLayout.cpp
+++ b/gui/ThemeLayout.cpp
@@ -123,7 +123,7 @@ int16 ThemeLayoutStacked::getParentHeight() {
#ifdef LAYOUT_DEBUG_DIALOG
void ThemeLayout::debugDraw(Graphics::Surface *screen, const Graphics::Font *font) {
- uint16 color = 0xFFFF;
+ uint32 color = 0xFFFFFFFF;
font->drawString(screen, getName(), _x, _y, _w, color, Graphics::kTextAlignRight, 0, true);
screen->hLine(_x, _y, _x + _w, color);
screen->hLine(_x, _y + _h, _x + _w , color);
diff --git a/gui/ThemeLayout.h b/gui/ThemeLayout.h
index ba28fae1ac..e738002aa6 100644
--- a/gui/ThemeLayout.h
+++ b/gui/ThemeLayout.h
@@ -29,7 +29,7 @@
#ifdef LAYOUT_DEBUG_DIALOG
namespace Graphics {
-class Surface;
+struct Surface;
}
#endif
@@ -45,7 +45,8 @@ public:
kLayoutMain,
kLayoutVertical,
kLayoutHorizontal,
- kLayoutWidget
+ kLayoutWidget,
+ kLayoutTabWidget
};
ThemeLayout(ThemeLayout *p) :
@@ -223,6 +224,41 @@ protected:
Common::String _name;
};
+class ThemeLayoutTabWidget : public ThemeLayoutWidget {
+ int _tabHeight;
+
+public:
+ ThemeLayoutTabWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, int tabHeight):
+ ThemeLayoutWidget(p, name, w, h, align) {
+ _tabHeight = tabHeight;
+ }
+
+ void reflowLayout() {
+ for (uint i = 0; i < _children.size(); ++i) {
+ _children[i]->resetLayout();
+ _children[i]->reflowLayout();
+ }
+ }
+
+ virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) {
+ if (ThemeLayoutWidget::getWidgetData(name, x, y, w, h)) {
+ h -= _tabHeight;
+ return true;
+ }
+
+ return false;
+ }
+
+protected:
+ LayoutType getLayoutType() { return kLayoutTabWidget; }
+
+ ThemeLayout *makeClone(ThemeLayout *newParent) {
+ ThemeLayoutTabWidget *n = new ThemeLayoutTabWidget(*this);
+ n->_parent = newParent;
+ return n;
+ }
+};
+
class ThemeLayoutSpacing : public ThemeLayout {
public:
ThemeLayoutSpacing(ThemeLayout *p, int size) : ThemeLayout(p) {
diff --git a/gui/Tooltip.cpp b/gui/Tooltip.cpp
index ba313ee34f..09ad7ce5ca 100644
--- a/gui/Tooltip.cpp
+++ b/gui/Tooltip.cpp
@@ -32,7 +32,7 @@ namespace GUI {
Tooltip::Tooltip() :
- Dialog(-1, -1, -1, -1), _maxWidth(-1) {
+ Dialog(-1, -1, -1, -1), _maxWidth(-1), _parent(NULL), _xdelta(0), _ydelta(0) {
_backgroundType = GUI::ThemeEngine::kDialogBackgroundTooltip;
}
diff --git a/gui/Tooltip.h b/gui/Tooltip.h
index 58b6d8a429..60688412e6 100644
--- a/gui/Tooltip.h
+++ b/gui/Tooltip.h
@@ -41,6 +41,8 @@ public:
void setup(Dialog *parent, Widget *widget, int x, int y);
void drawDialog();
+
+ virtual void receivedFocus(int x = -1, int y = -1) {}
protected:
virtual void handleMouseDown(int x, int y, int button, int clickCount) {
close();
@@ -64,7 +66,6 @@ protected:
}
virtual void handleMouseMoved(int x, int y, int button) {
close();
- _parent->handleMouseMoved(x + (getAbsX() - _parent->getAbsX()), y + (getAbsY() - _parent->getAbsY()), button);
}
int _maxWidth;
diff --git a/gui/credits.h b/gui/credits.h
index cb9a10fec4..c2c4c84ec6 100644
--- a/gui/credits.h
+++ b/gui/credits.h
@@ -58,6 +58,7 @@ static const char *credits[] = {
"C1""AGI",
"C0""Stuart George",
"C0""Matthew Hoops",
+"C2""(retired)",
"C0""Filippos Karapetis",
"C0""Martin Kiewitz",
"C0""Pawel Kolodziejski",
@@ -127,6 +128,7 @@ static const char *credits[] = {
"C1""Drascula",
"C0""Filippos Karapetis",
"C0""Pawel Kolodziejski",
+"C0""Thierry Crozat",
"",
"C1""DreamWeb",
"A0""Torbjorn Andersson",
@@ -137,6 +139,11 @@ static const char *credits[] = {
"C2""(retired)",
"C0""Willem Jan Palenstijn",
"",
+"C1""Gnap",
+"A0""Arnaud Boutonne",
+"C0""Arnaud Boutonn\351",
+"C0""Benjamin Haisch",
+"",
"C1""Gob",
"A0""Torbjorn Andersson",
"C0""Torbj\366rn Andersson",
@@ -173,6 +180,7 @@ static const char *credits[] = {
"",
"C1""Lastexpress",
"C0""Matthew Hoops",
+"C2""(retired)",
"C0""Jordi Vilalta Prat",
"C0""Julien Templier",
"",
@@ -192,6 +200,7 @@ static const char *credits[] = {
"C1""Mohawk",
"C0""Bastien Bouclet",
"C0""Matthew Hoops",
+"C2""(retired)",
"C0""Filippos Karapetis",
"C0""Alyssa Milburn",
"C0""Eugene Sandulenko",
@@ -211,6 +220,7 @@ static const char *credits[] = {
"",
"C1""Pegasus",
"C0""Matthew Hoops",
+"C2""(retired)",
"",
"C1""Queen",
"C0""David Eriksson",
@@ -343,6 +353,7 @@ static const char *credits[] = {
"C1""Android",
"C0""Andre Heider",
"C0""Angus Lees",
+"C0""Lubomyr Lisen",
"",
"C1""Dreamcast",
"C0""Marcus Comstedt",
@@ -366,6 +377,9 @@ static const char *credits[] = {
"C2""(retired)",
"C0""Tarek Soliman",
"",
+"C1""Nintendo 3DS",
+"C0""Thomas Edvalson",
+"",
"C1""Nintendo 64",
"C0""Fabio Battaglia",
"",
@@ -477,7 +491,7 @@ static const char *credits[] = {
"C0""Joachim Eberhard",
"C2""Numerous contributions to documentation (retired)",
"C0""Matthew Hoops",
-"C2""Wiki editor",
+"C2""Numerous contributions to documentation (retired)",
"",
"C1""Retired Team Members",
"C0""Chris Apers",
@@ -535,6 +549,7 @@ static const char *credits[] = {
"C0""Max Horn",
"C2""(retired)",
"C0""Oystein Eftevaag",
+"C0""Thierry Crozat",
"",
"C1""Mandriva",
"C0""Dominik Scherer",
diff --git a/gui/debugger.cpp b/gui/debugger.cpp
index c9b435963d..72d05e2973 100644
--- a/gui/debugger.cpp
+++ b/gui/debugger.cpp
@@ -42,6 +42,7 @@
#elif defined(USE_READLINE)
#include <readline/readline.h>
#include <readline/history.h>
+ #include "common/events.h"
#endif
@@ -191,6 +192,15 @@ char *readline_completionFunction(const char *text, int state) {
return g_readline_debugger->readlineComplete(text, state);
}
+void readline_eventFunction() {
+ Common::EventManager *eventMan = g_system->getEventManager();
+
+ Common::Event event;
+ while (eventMan->pollEvent(event)) {
+ // drop all events
+ }
+}
+
#ifdef USE_READLINE_INT_COMPLETION
typedef int RLCompFunc_t(const char *, int);
#else
@@ -228,6 +238,7 @@ void Debugger::enter() {
g_readline_debugger = this;
rl_completion_entry_function = (RLCompFunc_t *)&readline_completionFunction;
+ rl_event_hook = (rl_hook_func_t *)&readline_eventFunction;
char *line_read = 0;
do {
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index 315c24e9bf..523227a237 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -51,6 +51,8 @@ Dialog::Dialog(int x, int y, int w, int h)
// will for example crash after returning to the launcher when the user
// started a 640x480 game with a non 1x scaler.
g_gui.checkScreenChange();
+
+ _result = -1;
}
Dialog::Dialog(const Common::String &name)
@@ -66,6 +68,8 @@ Dialog::Dialog(const Common::String &name)
// Fixes bug #1590596: "HE: When 3x graphics are choosen, F5 crashes game"
// and bug #1595627: "SCUMM: F5 crashes game (640x480)"
g_gui.checkScreenChange();
+
+ _result = -1;
}
int Dialog::runModal() {
@@ -109,16 +113,18 @@ void Dialog::reflowLayout() {
// changed, so any cached image may be invalid. The subsequent redraw
// should be treated as the very first draw.
+ GuiObject::reflowLayout();
+
Widget *w = _firstWidget;
while (w) {
w->reflowLayout();
w = w->_next;
}
-
- GuiObject::reflowLayout();
}
void Dialog::lostFocus() {
+ _dragWidget = NULL;
+
if (_tickleWidget) {
_tickleWidget->lostFocus();
}
diff --git a/gui/dialog.h b/gui/dialog.h
index 593ee13458..0e06effabd 100644
--- a/gui/dialog.h
+++ b/gui/dialog.h
@@ -82,7 +82,7 @@ public:
virtual void reflowLayout();
virtual void lostFocus();
- virtual void receivedFocus() {}
+ virtual void receivedFocus(int x = -1, int y = -1) { if (x >= 0 && y >= 0) handleMouseMoved(x, y, 0); }
protected:
virtual void open();
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 20c6d3fa13..9acd9434ff 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -281,14 +281,9 @@ void GuiManager::runLoop() {
redraw();
}
- _lastMousePosition.x = _lastMousePosition.y = -1;
- _lastMousePosition.time = 0;
-
Common::EventManager *eventMan = _system->getEventManager();
uint32 lastRedraw = 0;
- const uint32 waitTime = 1000 / 45;
-
- bool tooltipCheck = false;
+ const uint32 waitTime = 1000 / 60;
while (!_dialogStack.empty() && activeDialog == getTopDialog() && !eventMan->shouldQuit()) {
redraw();
@@ -304,9 +299,9 @@ void GuiManager::runLoop() {
// _system->updateScreen();
if (lastRedraw + waitTime < _system->getMillis(true)) {
+ lastRedraw = _system->getMillis(true);
_theme->updateScreen();
_system->updateScreen();
- lastRedraw = _system->getMillis(true);
}
Common::Event event;
@@ -336,19 +331,14 @@ void GuiManager::runLoop() {
processEvent(event, activeDialog);
- if (event.type == Common::EVENT_MOUSEMOVE) {
- tooltipCheck = true;
- }
-
-
if (lastRedraw + waitTime < _system->getMillis(true)) {
+ lastRedraw = _system->getMillis(true);
_theme->updateScreen();
_system->updateScreen();
- lastRedraw = _system->getMillis(true);
}
}
- if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) {
+ if (_lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) {
Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y);
if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) {
Tooltip *tooltip = new Tooltip();
@@ -415,7 +405,7 @@ void GuiManager::restoreState() {
}
void GuiManager::openDialog(Dialog *dialog) {
- dialog->receivedFocus();
+ giveFocusToDialog(dialog);
if (!_dialogStack.empty())
getTopDialog()->lostFocus();
@@ -439,8 +429,10 @@ void GuiManager::closeTopDialog() {
// Remove the dialog from the stack
_dialogStack.pop()->lostFocus();
- if (!_dialogStack.empty())
- getTopDialog()->receivedFocus();
+ if (!_dialogStack.empty()) {
+ Dialog *dialog = getTopDialog();
+ giveFocusToDialog(dialog);
+ }
if (_redrawStatus != kRedrawFull)
_redrawStatus = kRedrawCloseDialog;
@@ -515,6 +507,7 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi
int button;
uint32 time;
Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y);
+
switch (event.type) {
case Common::EVENT_KEYDOWN:
activeDialog->handleKeyDown(event.kbd);
@@ -523,12 +516,12 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi
activeDialog->handleKeyUp(event.kbd);
break;
case Common::EVENT_MOUSEMOVE:
+ _globalMousePosition.x = event.mouse.x;
+ _globalMousePosition.y = event.mouse.y;
activeDialog->handleMouseMoved(mouse.x, mouse.y, 0);
if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) {
- _lastMousePosition.x = mouse.x;
- _lastMousePosition.y = mouse.y;
- _lastMousePosition.time = _system->getMillis(true);
+ setLastMousePos(mouse.x, mouse.y);
}
break;
@@ -571,4 +564,23 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi
}
}
+void GuiManager::doFullRedraw() {
+ _redrawStatus = kRedrawFull;
+ redraw();
+ _system->updateScreen();
+}
+
+void GuiManager::giveFocusToDialog(Dialog *dialog) {
+ int16 dialogX = _globalMousePosition.x - dialog->_x;
+ int16 dialogY = _globalMousePosition.y - dialog->_y;
+ dialog->receivedFocus(dialogX, dialogY);
+ setLastMousePos(dialogX, dialogY);
+}
+
+void GuiManager::setLastMousePos(int16 x, int16 y) {
+ _lastMousePosition.x = x;
+ _lastMousePosition.y = y;
+ _lastMousePosition.time = _system->getMillis(true);
+}
+
} // End of namespace GUI
diff --git a/gui/gui-manager.h b/gui/gui-manager.h
index 26c8d6def9..4dc9af95fb 100644
--- a/gui/gui-manager.h
+++ b/gui/gui-manager.h
@@ -73,6 +73,7 @@ public:
void runLoop();
void processEvent(const Common::Event &event, Dialog *const activeDialog);
+ void doFullRedraw();
bool isActive() const { return ! _dialogStack.empty(); }
@@ -124,11 +125,12 @@ protected:
bool _useStdCursor;
// position and time of last mouse click (used to detect double clicks)
- struct {
+ struct MousePos {
+ MousePos() : x(-1), y(-1), count(0) { time = 0; }
int16 x, y; // Position of mouse when the click occurred
uint32 time; // Time
int count; // How often was it already pressed?
- } _lastClick, _lastMousePosition;
+ } _lastClick, _lastMousePosition, _globalMousePosition;
// mouse cursor state
int _cursorAnimateCounter;
@@ -155,6 +157,9 @@ protected:
Dialog *getTopDialog() const;
void screenChange();
+
+ void giveFocusToDialog(Dialog *dialog);
+ void setLastMousePos(int16 x, int16 y);
};
} // End of namespace GUI
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index bae894cba1..9a3300b11f 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -282,6 +282,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
//
// 6) The MIDI tab
//
+ _globalMIDIOverride = NULL;
if (!_guioptions.contains(GUIO_NOMIDI)) {
tab->addTab(_("MIDI"));
@@ -296,6 +297,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
//
// 7) The MT-32 tab
//
+ _globalMT32Override = NULL;
if (!_guioptions.contains(GUIO_NOMIDI)) {
tab->addTab(_("MT-32"));
diff --git a/gui/module.mk b/gui/module.mk
index bbb3def96d..6cbc63d24d 100644
--- a/gui/module.mk
+++ b/gui/module.mk
@@ -30,6 +30,7 @@ MODULE_OBJS := \
widgets/list.o \
widgets/popup.o \
widgets/scrollbar.o \
+ widgets/scrollcontainer.o \
widgets/tab.o
# HACK: create_project's XCode generator relies on the following ifdef
@@ -65,5 +66,10 @@ MODULE_OBJS += \
fluidsynth-dialog.o
endif
+ifdef USE_UPDATES
+MODULE_OBJS += \
+ updates-dialog.o
+endif
+
# Include common rules
include $(srcdir)/rules.mk
diff --git a/gui/object.cpp b/gui/object.cpp
index ef2cc9d6e0..de66d95492 100644
--- a/gui/object.cpp
+++ b/gui/object.cpp
@@ -44,19 +44,6 @@ void GuiObject::reflowLayout() {
if (!g_gui.xmlEval()->getWidgetData(_name, _x, _y, _w, _h)) {
error("Could not load widget position for '%s'", _name.c_str());
}
-
- if (_x < 0)
- error("Widget <%s> has x < 0 (%d)", _name.c_str(), _x);
- if (_x >= g_gui.getWidth())
- error("Widget <%s> has x > %d (%d)", _name.c_str(), g_gui.getWidth(), _x);
- if (_x + _w > g_gui.getWidth())
- error("Widget <%s> has x + w > %d (%d)", _name.c_str(), g_gui.getWidth(), _x + _w);
- if (_y < 0)
- error("Widget <%s> has y < 0 (%d)", _name.c_str(), _y);
- if (_y >= g_gui.getHeight())
- error("Widget <%s> has y > %d (%d)", _name.c_str(), g_gui.getHeight(), _y);
- if (_y + _h > g_gui.getHeight())
- error("Widget <%s> has y + h > %d (%d)", _name.c_str(), g_gui.getHeight(), _y + _h);
}
}
diff --git a/gui/options.cpp b/gui/options.cpp
index ba247e5f15..e410971818 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -36,6 +36,7 @@
#include "common/system.h"
#include "common/textconsole.h"
#include "common/translation.h"
+#include "common/updates.h"
#include "audio/mididrv.h"
#include "audio/musicplugin.h"
@@ -61,7 +62,8 @@ enum {
kChooseExtraDirCmd = 'chex',
kExtraPathClearCmd = 'clex',
kChoosePluginsDirCmd = 'chpl',
- kChooseThemeCmd = 'chtf'
+ kChooseThemeCmd = 'chtf',
+ kUpdatesCheckCmd = 'updc'
};
enum {
@@ -70,7 +72,7 @@ enum {
kSubtitlesBoth
};
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
enum {
kChooseKeyMappingCmd = 'chma'
};
@@ -110,6 +112,7 @@ void OptionsDialog::init() {
_fullscreenCheckbox = 0;
_aspectCheckbox = 0;
_enableAudioSettings = false;
+ _midiTabId = 0;
_midiPopUp = 0;
_midiPopUpDesc = 0;
_oplPopUp = 0;
@@ -142,6 +145,7 @@ void OptionsDialog::init() {
_speechVolumeSlider = 0;
_speechVolumeLabel = 0;
_muteCheckbox = 0;
+ _enableSubtitleSettings = false;
_subToggleDesc = 0;
_subToggleGroup = 0;
_subToggleSubOnly = 0;
@@ -150,6 +154,8 @@ void OptionsDialog::init() {
_subSpeedDesc = 0;
_subSpeedSlider = 0;
_subSpeedLabel = 0;
+
+ _pathsTabId = 0;
_oldTheme = g_gui.theme()->getThemeId();
// Retrieve game GUI options
@@ -204,12 +210,12 @@ void OptionsDialog::open() {
_renderModePopUp->setSelectedTag(sel);
}
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ONLY_FULLSCREEN
_fullscreenCheckbox->setState(true);
_fullscreenCheckbox->setEnabled(false);
- _aspectCheckbox->setState(false);
+ _aspectCheckbox->setState(ConfMan.getBool("aspect_ratio", _domain));
_aspectCheckbox->setEnabled(false);
-#else // !SMALL_SCREEN_DEVICE
+#else // !GUI_ONLY_FULLSCREEN
// Fullscreen setting
_fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain));
@@ -221,7 +227,7 @@ void OptionsDialog::open() {
_aspectCheckbox->setEnabled(true);
_aspectCheckbox->setState(ConfMan.getBool("aspect_ratio", _domain));
}
-#endif // SMALL_SCREEN_DEVICE
+#endif // GUI_ONLY_FULLSCREEN
}
@@ -604,7 +610,7 @@ void OptionsDialog::setGraphicSettingsState(bool enabled) {
_gfxPopUp->setEnabled(enabled);
_renderModePopUpDesc->setEnabled(enabled);
_renderModePopUp->setEnabled(enabled);
-#ifndef SMALL_SCREEN_DEVICE
+#ifndef GUI_ENABLE_KEYSDIALOG
_fullscreenCheckbox->setEnabled(enabled);
if (_guioptions.contains(GUIO_NOASPECT))
_aspectCheckbox->setEnabled(false);
@@ -868,10 +874,6 @@ void OptionsDialog::addMIDIControls(GuiObject *boss, const Common::String &prefi
_midiGainSlider->setMaxValue(1000);
_midiGainLabel = new StaticTextWidget(boss, prefix + "mcMidiGainLabel", "1.00");
-#ifdef USE_FLUIDSYNTH
- new ButtonWidget(boss, prefix + "mcFluidSynthSettings", _("FluidSynth Settings"), 0, kFluidSynthSettingsCmd);
-#endif
-
_enableMIDISettings = true;
}
@@ -1109,6 +1111,10 @@ GlobalOptionsDialog::GlobalOptionsDialog()
_midiTabId = tab->addTab(_("MIDI"));
addMIDIControls(tab, "GlobalOptions_MIDI.");
+#ifdef USE_FLUIDSYNTH
+ new ButtonWidget(tab, "GlobalOptions_MIDI.mcFluidSynthSettings", _("FluidSynth Settings"), 0, kFluidSynthSettingsCmd);
+#endif
+
//
// 4) The MT-32 tab
//
@@ -1194,7 +1200,7 @@ GlobalOptionsDialog::GlobalOptionsDialog()
_autosavePeriodPopUp->appendEntry(_(savePeriodLabels[i]), savePeriodValues[i]);
}
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
new ButtonWidget(tab, "GlobalOptions_Misc.KeysButton", _("Keys"), 0, kChooseKeyMappingCmd);
#endif
@@ -1229,6 +1235,22 @@ GlobalOptionsDialog::GlobalOptionsDialog()
#endif // USE_TRANSLATION
+#ifdef USE_UPDATES
+ _updatesPopUpDesc = new StaticTextWidget(tab, "GlobalOptions_Misc.UpdatesPopupDesc", _("Update check:"), _("How often to check ScummVM updates"));
+ _updatesPopUp = new PopUpWidget(tab, "GlobalOptions_Misc.UpdatesPopup");
+
+ const int *vals = Common::UpdateManager::getUpdateIntervals();
+
+ while (*vals != -1) {
+ _updatesPopUp->appendEntry(Common::UpdateManager::updateIntervalToString(*vals), *vals);
+ vals++;
+ }
+
+ _updatesPopUp->setSelectedTag(Common::UpdateManager::normalizeInterval(ConfMan.getInt("updates_check")));
+
+ new ButtonWidget(tab, "GlobalOptions_Misc.UpdatesCheckManuallyButton", _("Check now"), 0, kUpdatesCheckCmd);
+#endif
+
// Activate the first tab
tab->setActiveTab(0);
_tabWidget = tab;
@@ -1237,7 +1259,7 @@ GlobalOptionsDialog::GlobalOptionsDialog()
new ButtonWidget(this, "GlobalOptions.Cancel", _("Cancel"), 0, kCloseCmd);
new ButtonWidget(this, "GlobalOptions.Ok", _("OK"), 0, kOKCmd);
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
_keysDialog = new KeysDialog();
#endif
@@ -1247,7 +1269,7 @@ GlobalOptionsDialog::GlobalOptionsDialog()
}
GlobalOptionsDialog::~GlobalOptionsDialog() {
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
delete _keysDialog;
#endif
@@ -1367,6 +1389,19 @@ void GlobalOptionsDialog::close() {
}
#endif // USE_TRANSLATION
+#ifdef USE_UPDATES
+ ConfMan.setInt("updates_check", _updatesPopUp->getSelectedTag());
+
+ if (g_system->getUpdateManager()) {
+ if (_updatesPopUp->getSelectedTag() == Common::UpdateManager::kUpdateIntervalNotSupported) {
+ g_system->getUpdateManager()->setAutomaticallyChecksForUpdates(Common::UpdateManager::kUpdateStateDisabled);
+ } else {
+ g_system->getUpdateManager()->setAutomaticallyChecksForUpdates(Common::UpdateManager::kUpdateStateEnabled);
+ g_system->getUpdateManager()->setUpdateCheckInterval(_updatesPopUp->getSelectedTag());
+ }
+ }
+#endif
+
}
OptionsDialog::close();
}
@@ -1478,7 +1513,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
}
break;
}
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
case kChooseKeyMappingCmd:
_keysDialog->runModal();
break;
@@ -1488,6 +1523,12 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
_fluidSynthSettingsDialog->runModal();
break;
#endif
+#ifdef USE_UPDATES
+ case kUpdatesCheckCmd:
+ if (g_system->getUpdateManager())
+ g_system->getUpdateManager()->checkForUpdates();
+ break;
+#endif
default:
OptionsDialog::handleCommand(sender, cmd, data);
}
diff --git a/gui/options.h b/gui/options.h
index 1e65bfd134..294b41794b 100644
--- a/gui/options.h
+++ b/gui/options.h
@@ -29,7 +29,7 @@
#include "common/str.h"
#include "audio/mididrv.h"
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
#include "gui/KeysDialog.h"
#endif
@@ -210,7 +210,7 @@ public:
virtual void reflowLayout();
protected:
-#ifdef SMALL_SCREEN_DEVICE
+#ifdef GUI_ENABLE_KEYSDIALOG
KeysDialog *_keysDialog;
#endif
#ifdef USE_FLUIDSYNTH
@@ -236,6 +236,11 @@ protected:
PopUpWidget *_autosavePeriodPopUp;
StaticTextWidget *_guiLanguagePopUpDesc;
PopUpWidget *_guiLanguagePopUp;
+
+#ifdef USE_UPDATES
+ StaticTextWidget *_updatesPopUpDesc;
+ PopUpWidget *_updatesPopUp;
+#endif
};
} // End of namespace GUI
diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp
index 9557da1206..933667186e 100644
--- a/gui/predictivedialog.cpp
+++ b/gui/predictivedialog.cpp
@@ -142,6 +142,9 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
_numMemory = 0;
_navigationWithKeys = false;
+
+ _curPressedButton = kNoAct;
+ _needRefresh = true;
}
PredictiveDialog::~PredictiveDialog() {
@@ -190,7 +193,7 @@ void PredictiveDialog::saveUserDictToFile() {
void PredictiveDialog::handleKeyUp(Common::KeyState state) {
if (_curPressedButton != kNoAct && !_needRefresh) {
- _button[_curPressedButton]->startAnimatePressedState();
+ _button[_curPressedButton]->setUnpressedState();
processButton(_curPressedButton);
}
}
@@ -352,7 +355,7 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) {
}
if (_lastButton != _curPressedButton)
- _button[_lastButton]->stopAnimatePressedState();
+ _button[_lastButton]->setUnpressedState();
if (_curPressedButton != kNoAct && !_needRefresh)
_button[_curPressedButton]->setPressedState();
@@ -604,18 +607,6 @@ void PredictiveDialog::processButton(ButtonId button) {
}
}
-void PredictiveDialog::handleTickle() {
- if (_lastTime) {
- if ((_curTime - _lastTime) > kRepeatDelay) {
- _lastTime = 0;
- }
- }
-
- if (getTickleWidget()) {
- getTickleWidget()->handleTickle();
- }
-}
-
void PredictiveDialog::mergeDicts() {
_unitedDict.dictLineCount = _predictiveDict.dictLineCount + _userDict.dictLineCount;
_unitedDict.dictLine = (char **)calloc(_unitedDict.dictLineCount, sizeof(char *));
diff --git a/gui/predictivedialog.h b/gui/predictivedialog.h
index 4c167c3efa..1f6bdf84e0 100644
--- a/gui/predictivedialog.h
+++ b/gui/predictivedialog.h
@@ -43,7 +43,6 @@ public:
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
virtual void handleKeyUp(Common::KeyState state);
virtual void handleKeyDown(Common::KeyState state);
- virtual void handleTickle();
const char *getResult() const { return _predictiveResult; }
diff --git a/gui/recorderdialog.cpp b/gui/recorderdialog.cpp
index 2d74cebbb6..c08b3e149a 100644
--- a/gui/recorderdialog.cpp
+++ b/gui/recorderdialog.cpp
@@ -33,7 +33,6 @@
#include "gui/editrecorddialog.h"
#include "gui/EventRecorder.h"
#include "gui/message.h"
-#include "gui/saveload.h"
#include "common/system.h"
#include "gui/ThemeEval.h"
#include "gui/gui-manager.h"
diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp
index a333c5fe57..3d4adfff2b 100644
--- a/gui/saveload-dialog.cpp
+++ b/gui/saveload-dialog.cpp
@@ -932,6 +932,8 @@ SavenameDialog::SavenameDialog()
new ButtonWidget(this, "SavenameDialog.Ok", _("OK"), 0, kOKCmd);
_description = new EditTextWidget(this, "SavenameDialog.Description", Common::String(), 0, 0, kOKCmd);
+
+ _targetSlot = 0;
}
void SavenameDialog::setDescription(const Common::String &desc) {
diff --git a/gui/saveload.cpp b/gui/saveload.cpp
index c1c1d12ec5..b94d30289b 100644
--- a/gui/saveload.cpp
+++ b/gui/saveload.cpp
@@ -25,7 +25,6 @@
#include "gui/saveload.h"
#include "gui/saveload-dialog.h"
-#include "gui/gui-manager.h"
#include "engines/metaengine.h"
diff --git a/gui/saveload.h b/gui/saveload.h
index 22c26d4c5e..01a78c4924 100644
--- a/gui/saveload.h
+++ b/gui/saveload.h
@@ -23,7 +23,7 @@
#ifndef GUI_SAVELOAD_H
#define GUI_SAVELOAD_H
-#include "gui/dialog.h"
+#include "common/str.h"
#include "engines/metaengine.h"
namespace GUI {
diff --git a/gui/themes/default.inc b/gui/themes/default.inc
index e367bcb3c7..c0ea733de8 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -798,7 +798,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"</dialog>"
"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'>"
"<layout type='vertical' padding='0,0,0,0'>"
-"<widget name='TabWidget'/>"
+"<widget name='TabWidget' type='TabWidget'/>"
"<layout type='horizontal' padding='16,16,16,16'>"
"<space/>"
"<widget name='Cancel' "
@@ -1076,6 +1076,17 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"type='PopUp' "
"/>"
"</layout>"
+"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>"
+"<widget name='UpdatesPopupDesc' "
+"type='OptionsLabel' "
+"/>"
+"<widget name='UpdatesPopup' "
+"type='PopUp' "
+"/>"
+"<widget name='UpdatesCheckManuallyButton' "
+"type='Button' "
+"/>"
+"</layout>"
"<widget name='KeysButton' "
"type='Button' "
"/>"
@@ -1107,7 +1118,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"</dialog>"
"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'>"
"<layout type='vertical' padding='0,0,0,0' spacing='16'>"
-"<widget name='TabWidget'/>"
+"<widget name='TabWidget' type='TabWidget'/>"
"<layout type='horizontal' padding='16,16,16,4'>"
"<space/>"
"<widget name='Cancel' "
@@ -1394,7 +1405,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"</dialog>"
"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>"
"<layout type='vertical' padding='0,0,0,0'>"
-"<widget name='TabWidget'/>"
+"<widget name='TabWidget' type='TabWidget'/>"
"<layout type='horizontal' padding='16,16,16,16'>"
"<space/>"
"<widget name='ResetSettings' "
@@ -1964,7 +1975,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"padding='0,0,2,0' "
"/>"
"<widget name='TabWidget.Body' "
-"padding='0,0,0,-8' "
+"padding='0,0,0,0' "
"/>"
"<widget name='TabWidget.NavButton' "
"size='32,18' "
@@ -2082,7 +2093,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"</dialog>"
"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'>"
"<layout type='vertical' padding='0,0,0,0'>"
-"<widget name='TabWidget'/>"
+"<widget name='TabWidget' type='TabWidget'/>"
"<layout type='horizontal' padding='8,8,8,8'>"
"<space/>"
"<widget name='Cancel' "
@@ -2365,6 +2376,19 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"type='PopUp' "
"/>"
"</layout>"
+"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>"
+"<widget name='UpdatesPopupDesc' "
+"width='80' "
+"height='Globals.Line.Height' "
+"textalign='right' "
+"/>"
+"<widget name='UpdatesPopup' "
+"type='PopUp' "
+"/>"
+"<widget name='UpdatesCheckManuallyButton' "
+"type='Button' "
+"/>"
+"</layout>"
"<widget name='KeysButton' "
"type='Button' "
"/>"
@@ -2396,7 +2420,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"</dialog>"
"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'>"
"<layout type='vertical' padding='0,0,0,0' spacing='16'>"
-"<widget name='TabWidget'/>"
+"<widget name='TabWidget' type='TabWidget'/>"
"<layout type='horizontal' padding='8,8,8,8'>"
"<space/>"
"<widget name='Cancel' "
@@ -2692,7 +2716,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>"
"</dialog>"
"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>"
"<layout type='vertical' padding='0,0,0,0'>"
-"<widget name='TabWidget'/>"
+"<widget name='TabWidget' type='TabWidget'/>"
"<layout type='horizontal' padding='8,8,8,8'>"
"<space/>"
"<widget name='ResetSettings' "
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index 1d8b8dad05..561f2a5dd3 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 18c2a1f889..5172326859 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -222,7 +222,7 @@
<dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '16, 16, 16, 16'>
<space/>
<widget name = 'Cancel'
@@ -507,6 +507,17 @@
type = 'PopUp'
/>
</layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
+ <widget name = 'UpdatesPopupDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'UpdatesPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'UpdatesCheckManuallyButton'
+ type = 'Button'
+ />
+ </layout>
<widget name='KeysButton'
type='Button'
/>
@@ -540,7 +551,7 @@
<dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '16, 16, 16, 4'>
<space/>
<widget name = 'Cancel'
@@ -839,7 +850,7 @@
<dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '16, 16, 16, 16'>
<space/>
<widget name = 'ResetSettings'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 6cc9eed6b3..0013b91ee2 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -97,7 +97,7 @@
padding = '0, 0, 2, 0'
/>
<widget name = 'TabWidget.Body'
- padding = '0, 0, 0, -8'
+ padding = '0, 0, 0, 0'
/>
<widget name = 'TabWidget.NavButton'
size = '32, 18'
@@ -219,7 +219,7 @@
<dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
<widget name = 'Cancel'
@@ -510,6 +510,19 @@
type = 'PopUp'
/>
</layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
+ <widget name = 'UpdatesPopupDesc'
+ width = '80'
+ height = 'Globals.Line.Height'
+ textalign = 'right'
+ />
+ <widget name = 'UpdatesPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'UpdatesCheckManuallyButton'
+ type = 'Button'
+ />
+ </layout>
<widget name='KeysButton'
type='Button'
/>
@@ -543,7 +556,7 @@
<dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
<widget name = 'Cancel'
@@ -850,7 +863,7 @@
<dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
<widget name = 'ResetSettings'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 43826abf5e..d80c481ffc 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index fd6a3c5cd2..026fa7bc64 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -236,7 +236,7 @@
<dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '16, 16, 16, 16'>
<space/>
<widget name = 'Cancel'
@@ -521,6 +521,17 @@
type = 'PopUp'
/>
</layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
+ <widget name = 'UpdatesPopupDesc'
+ type = 'OptionsLabel'
+ />
+ <widget name = 'UpdatesPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'UpdatesCheckManuallyButton'
+ type = 'Button'
+ />
+ </layout>
<widget name='KeysButton'
type='Button'
/>
@@ -554,7 +565,7 @@
<dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '16, 16, 16, 4'>
<space/>
<widget name = 'Cancel'
@@ -853,7 +864,7 @@
<dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '16, 16, 16, 16'>
<space/>
<widget name = 'ResetSettings'
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index 9d8f79795c..169e61a9bb 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -95,7 +95,7 @@
padding = '0, 0, 2, 0'
/>
<widget name = 'TabWidget.Body'
- padding = '0, 0, 0, -8'
+ padding = '0, 0, 0, 0'
/>
<widget name = 'TabWidget.NavButton'
size = '32, 18'
@@ -217,7 +217,7 @@
<dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
<widget name = 'Cancel'
@@ -508,6 +508,19 @@
type = 'PopUp'
/>
</layout>
+ <layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
+ <widget name = 'UpdatesPopupDesc'
+ width = '80'
+ height = 'Globals.Line.Height'
+ textalign = 'right'
+ />
+ <widget name = 'UpdatesPopup'
+ type = 'PopUp'
+ />
+ <widget name = 'UpdatesCheckManuallyButton'
+ type = 'Button'
+ />
+ </layout>
<widget name='KeysButton'
type='Button'
/>
@@ -541,7 +554,7 @@
<dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
<widget name = 'Cancel'
@@ -848,7 +861,7 @@
<dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
- <widget name = 'TabWidget'/>
+ <widget name = 'TabWidget' type = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
<widget name = 'ResetSettings'
diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat
index 2378bc4e13..7533d41454 100644
--- a/gui/themes/translations.dat
+++ b/gui/themes/translations.dat
Binary files differ
diff --git a/gui/updates-dialog.cpp b/gui/updates-dialog.cpp
new file mode 100644
index 0000000000..b82ecc0402
--- /dev/null
+++ b/gui/updates-dialog.cpp
@@ -0,0 +1,148 @@
+/* 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.
+ *
+ */
+
+#include "common/system.h"
+#include "common/translation.h"
+#include "common/updates.h"
+#include "common/config-manager.h"
+
+#include "gui/updates-dialog.h"
+#include "gui/gui-manager.h"
+#include "gui/ThemeEval.h"
+#include "gui/widgets/popup.h"
+
+namespace GUI {
+
+enum {
+ kYesCmd = 'YES ',
+ kNoCmd = 'NO ',
+ kCheckBoxCmd = 'CHK '
+};
+
+
+UpdatesDialog::UpdatesDialog() : Dialog(30, 20, 260, 124) {
+
+ const int screenW = g_system->getOverlayWidth();
+ const int screenH = g_system->getOverlayHeight();
+
+ int buttonWidth = g_gui.xmlEval()->getVar("Globals.Button.Width", 0);
+ int buttonHeight = g_gui.xmlEval()->getVar("Globals.Button.Height", 0);
+
+ const char *message = _(
+ "ScummVM now supports automatic check for updates\n"
+ "which requires access to the Internet.\n"
+ "\n"
+ "Would you like to enable this feature?");
+ const char *message2 = _("(You can always enable it in the options dialog on the Misc tab)");
+
+ // First, determine the size the dialog needs. For this we have to break
+ // down the string into lines, and taking the maximum of their widths.
+ // Using this, and accounting for the space the button(s) need, we can set
+ // the real size of the dialog
+ Common::Array<Common::String> lines, lines2;
+ int maxlineWidth = g_gui.getFont().wordWrapText(message, screenW - 2 * 20, lines);
+ int maxlineWidth2 = g_gui.getFont(ThemeEngine::kFontStyleTooltip).wordWrapText(message2, screenW - 2 * 20, lines2);
+
+ _w = MAX(MAX(maxlineWidth, maxlineWidth2), (2 * buttonWidth) + 10) + 20;
+
+ int lineCount = lines.size() + 1 + lines2.size();
+
+ _h = 16 + 3 * kLineHeight;
+ _h += buttonHeight + 8;
+
+ _h += lineCount * kLineHeight;
+
+ // Center the dialog
+ _x = (screenW - _w) / 2;
+ _y = (screenH - _h) / 2;
+
+ // Each line is represented by one static text item.
+ uint y = 10;
+ for (uint i = 0; i < lines.size(); i++) {
+ new StaticTextWidget(this, 10, y, maxlineWidth, kLineHeight,
+ lines[i], Graphics::kTextAlignCenter);
+ y += kLineHeight;
+ }
+ for (uint i = 0; i < lines2.size(); i++) {
+ new StaticTextWidget(this, 10, y, maxlineWidth2, kLineHeight,
+ lines2[i], Graphics::kTextAlignCenter, 0, ThemeEngine::kFontStyleTooltip);
+ y += kLineHeight;
+ }
+
+ y += kLineHeight;
+ _updatesCheckbox = new CheckboxWidget(this, 10, y, _w, kLineHeight, _("Check for updates automatically"), 0, kCheckBoxCmd);
+
+ y += kLineHeight + 3;
+
+ _updatesPopUp = new PopUpWidget(this, 10, y, _w - 20, g_gui.xmlEval()->getVar("Globals.PopUp.Height", kLineHeight));
+
+ const int *vals = Common::UpdateManager::getUpdateIntervals();
+
+ while (*vals != -1) {
+ _updatesPopUp->appendEntry(Common::UpdateManager::updateIntervalToString(*vals), *vals);
+ vals++;
+ }
+
+ _updatesPopUp->setSelectedTag(Common::UpdateManager::kUpdateIntervalOneWeek);
+
+ int yesButtonPos = (_w - (buttonWidth * 2)) / 2;
+ int noButtonPos = ((_w - (buttonWidth * 2)) / 2) + buttonWidth + 10;
+
+ _yesButton = new ButtonWidget(this, yesButtonPos, _h - buttonHeight - 8, buttonWidth, buttonHeight,
+ _("Proceed"), 0, kYesCmd, Common::ASCII_RETURN);
+ _noButton = new ButtonWidget(this, noButtonPos, _h - buttonHeight - 8, buttonWidth, buttonHeight,
+ _("Cancel"), 0, kNoCmd, Common::ASCII_ESCAPE);
+
+ _updatesPopUp->setEnabled(false);
+ _yesButton->setEnabled(false);
+}
+
+void UpdatesDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ if (cmd == kYesCmd) {
+ ConfMan.setInt("updates_check", _updatesPopUp->getSelectedTag());
+
+ if (g_system->getUpdateManager()) {
+ if (_updatesCheckbox->getState() == false ||
+ _updatesPopUp->getSelectedTag() == Common::UpdateManager::kUpdateIntervalNotSupported) {
+ g_system->getUpdateManager()->setAutomaticallyChecksForUpdates(Common::UpdateManager::kUpdateStateDisabled);
+ } else {
+ g_system->getUpdateManager()->setAutomaticallyChecksForUpdates(Common::UpdateManager::kUpdateStateEnabled);
+ g_system->getUpdateManager()->setUpdateCheckInterval(_updatesPopUp->getSelectedTag());
+ }
+ }
+ close();
+ } else if (cmd == kNoCmd) {
+ ConfMan.setInt("updates_check", Common::UpdateManager::kUpdateIntervalNotSupported);
+ g_system->getUpdateManager()->setAutomaticallyChecksForUpdates(Common::UpdateManager::kUpdateStateDisabled);
+
+ close();
+ } else if (cmd == kCheckBoxCmd) {
+ _updatesPopUp->setEnabled(_updatesCheckbox->getState());
+ _yesButton->setEnabled(_updatesCheckbox->getState());
+
+ draw();
+ } else {
+ Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+} // End of namespace GUI
diff --git a/engines/scumm/he/logic/moonbase.cpp b/gui/updates-dialog.h
index 29a0dde7a2..9c429c960c 100644
--- a/engines/scumm/he/logic/moonbase.cpp
+++ b/gui/updates-dialog.h
@@ -20,33 +20,35 @@
*
*/
-#include "scumm/he/intern_he.h"
-#include "scumm/he/logic_he.h"
+#ifndef GUI_UPDATES_DIALOG_H
+#define GUI_UPDATES_DIALOG_H
-namespace Scumm {
+#include "gui/dialog.h"
+
+namespace GUI {
+
+class CheckboxWidget;
+class CommandSender;
+class ButtonWidget;
+class PopUpWidget;
/**
- * Logic code for:
- * Moonbase Commander
+ * Wizard for updates opt-in
*/
-class LogicHEmoonbase : public LogicHE {
+class UpdatesDialog : public Dialog {
public:
- LogicHEmoonbase(ScummEngine_v90he *vm) : LogicHE(vm) {}
+ UpdatesDialog();
+ virtual ~UpdatesDialog() {}
- int versionID();
-};
+ void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
-int LogicHEmoonbase::versionID() {
- if (_vm->_game.features & GF_DEMO)
- return -100;
- else if (strcmp(_vm->_game.variant, "1.1") == 0)
- return 110;
- else
- return 100;
-}
+private:
+ PopUpWidget *_updatesPopUp;
+ ButtonWidget *_yesButton;
+ ButtonWidget *_noButton;
+ CheckboxWidget *_updatesCheckbox;
+};
-LogicHE *makeLogicHEmoonbase(ScummEngine_v90he *vm) {
- return new LogicHEmoonbase(vm);
-}
+} // End of namespace GUI
-} // End of namespace Scumm
+#endif
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 851774fd70..f2a29c3100 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -53,6 +53,31 @@ void Widget::init() {
_boss->_firstWidget = this;
}
+Common::Rect Widget::getBossClipRect() const {
+ int bx = _boss->getAbsX();
+ int by = _boss->getAbsY();
+ Common::Rect result = Common::Rect(bx, by, bx + _boss->getWidth(), by + _boss->getHeight());
+ bool needsClipping = false;
+
+ //check whether clipping area is inside the screen
+ if (result.left < 0 && (needsClipping = true))
+ warning("Widget <%s> has clipping area x < 0 (%d)", _name.c_str(), result.left);
+ if (result.left >= g_gui.getWidth() && (needsClipping = true))
+ warning("Widget <%s> has clipping area x > %d (%d)", _name.c_str(), g_gui.getWidth(), result.left);
+ if (result.right > g_gui.getWidth() && (needsClipping = true))
+ warning("Widget <%s> has clipping area x + w > %d (%d)", _name.c_str(), g_gui.getWidth(), result.right);
+ if (result.top < 0 && (needsClipping = true))
+ warning("Widget <%s> has clipping area y < 0 (%d)", _name.c_str(), result.top);
+ if (result.top >= g_gui.getHeight() && (needsClipping = true))
+ warning("Widget <%s> has clipping area y > %d (%d)", _name.c_str(), g_gui.getHeight(), result.top);
+ if (result.bottom > g_gui.getHeight() && (needsClipping = true))
+ warning("Widget <%s> has clipping area y + h > %d (%d)", _name.c_str(), g_gui.getHeight(), result.bottom);
+
+ if (needsClipping)
+ result.clip(g_gui.getWidth(), g_gui.getHeight());
+ return result;
+}
+
Widget::~Widget() {
delete _next;
_next = 0;
@@ -99,7 +124,7 @@ void Widget::draw() {
// Draw border
if (_flags & WIDGET_BORDER) {
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, ThemeEngine::kWidgetBackgroundBorder);
+ g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder);
_x += 4;
_y += 4;
_w -= 8;
@@ -131,7 +156,7 @@ void Widget::draw() {
Widget *Widget::findWidgetInChain(Widget *w, int x, int y) {
while (w) {
// Stop as soon as we find a widget that contains the point (x,y)
- if (x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->_h)
+ if (x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->getHeight())
break;
w = w->_next;
}
@@ -229,20 +254,22 @@ Common::String Widget::cleanupHotkey(const Common::String &label) {
#pragma mark -
-StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip)
+StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip, ThemeEngine::FontStyle font)
: Widget(boss, x, y, w, h, tooltip), _align(align) {
setFlags(WIDGET_ENABLED);
_type = kStaticTextWidget;
_label = text;
+ _font = font;
}
-StaticTextWidget::StaticTextWidget(GuiObject *boss, const Common::String &name, const Common::String &text, const char *tooltip)
+StaticTextWidget::StaticTextWidget(GuiObject *boss, const Common::String &name, const Common::String &text, const char *tooltip, ThemeEngine::FontStyle font)
: Widget(boss, name, tooltip) {
setFlags(WIDGET_ENABLED);
_type = kStaticTextWidget;
_label = text;
_align = g_gui.xmlEval()->getWidgetTextHAlign(name);
+ _font = font;
}
void StaticTextWidget::setValue(int value) {
@@ -263,21 +290,32 @@ void StaticTextWidget::setLabel(const Common::String &label) {
}
void StaticTextWidget::setAlign(Graphics::TextAlign align) {
- _align = align;
- // TODO: We should automatically redraw when the alignment is changed.
- // See setLabel() for more insights.
+ if (_align != align){
+ _align = align;
+
+ // same as setLabel() actually, the text
+ // would be redrawn on top of the old one so
+ // we add the CLEARBG flag
+ setFlags(WIDGET_CLEARBG);
+ draw();
+ clearFlags(WIDGET_CLEARBG);
+ }
+
}
void StaticTextWidget::drawWidget() {
- g_gui.theme()->drawText(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, _align);
+ g_gui.theme()->drawTextClip(
+ Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(),
+ _label, _state, _align, ThemeEngine::kTextInversionNone, 0, true, _font
+ );
}
#pragma mark -
ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &label, const char *tooltip, uint32 cmd, uint8 hotkey)
: StaticTextWidget(boss, x, y, w, h, cleanupHotkey(label), Graphics::kTextAlignCenter, tooltip), CommandSender(boss),
- _cmd(cmd), _hotkey(hotkey), _lastTime(0) {
+ _cmd(cmd), _hotkey(hotkey), _lastTime(0), _duringPress(false) {
if (hotkey == 0)
_hotkey = parseHotkey(label);
@@ -288,7 +326,7 @@ ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const Co
ButtonWidget::ButtonWidget(GuiObject *boss, const Common::String &name, const Common::String &label, const char *tooltip, uint32 cmd, uint8 hotkey)
: StaticTextWidget(boss, name, cleanupHotkey(label), tooltip), CommandSender(boss),
- _cmd(cmd), _hotkey(hotkey), _lastTime(0) {
+ _cmd(cmd), _hotkey(hotkey), _lastTime(0), _duringPress(false) {
if (hotkey == 0)
_hotkey = parseHotkey(label);
setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
@@ -296,18 +334,23 @@ ButtonWidget::ButtonWidget(GuiObject *boss, const Common::String &name, const Co
}
void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
- if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) {
- startAnimatePressedState();
+ if (isEnabled() && _duringPress && x >= 0 && x < _w && y >= 0 && y < _h) {
+ setUnpressedState();
sendCommand(_cmd, 0);
}
+ _duringPress = false;
}
void ButtonWidget::handleMouseDown(int x, int y, int button, int clickCount) {
+ _duringPress = true;
setPressedState();
}
void ButtonWidget::drawWidget() {
- g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, getFlags());
+ g_gui.theme()->drawButtonClip(
+ Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(),
+ _label, _state, getFlags()
+ );
}
void ButtonWidget::setLabel(const Common::String &label) {
@@ -340,39 +383,17 @@ void ButtonWidget::setHighLighted(bool enable) {
draw();
}
-void ButtonWidget::handleTickle() {
- if (_lastTime) {
- uint32 curTime = g_system->getMillis();
- if (curTime - _lastTime > kPressedButtonTime) {
- stopAnimatePressedState();
- }
- }
-}
-
void ButtonWidget::setPressedState() {
- wantTickle(true);
setFlags(WIDGET_PRESSED);
+ clearFlags(WIDGET_HILITED);
draw();
}
-void ButtonWidget::stopAnimatePressedState() {
- wantTickle(false);
- _lastTime = 0;
+void ButtonWidget::setUnpressedState() {
clearFlags(WIDGET_PRESSED);
draw();
}
-void ButtonWidget::startAnimatePressedState() {
- _lastTime = g_system->getMillis();
-}
-
-void ButtonWidget::wantTickle(bool tickled) {
- if (tickled)
- ((GUI::Dialog *)_boss)->setTickleWidget(this);
- else
- ((GUI::Dialog *)_boss)->unSetTickleWidget();
-}
-
#pragma mark -
PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip, uint32 cmd, uint8 hotkey)
@@ -428,7 +449,7 @@ void PicButtonWidget::setGfx(int w, int h, int r, int g, int b) {
}
void PicButtonWidget::drawWidget() {
- g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), "", _state, getFlags());
+ g_gui.theme()->drawButtonClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), "", _state, getFlags());
if (_gfx.getPixels()) {
// Check whether the set up surface needs to be converted to the GUI
@@ -441,7 +462,7 @@ void PicButtonWidget::drawWidget() {
const int x = _x + (_w - _gfx.w) / 2;
const int y = _y + (_h - _gfx.h) / 2;
- g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency);
+ g_gui.theme()->drawSurfaceClip(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), getBossClipRect(), _gfx, _state, _alpha, _transparency);
}
}
@@ -460,9 +481,10 @@ CheckboxWidget::CheckboxWidget(GuiObject *boss, const Common::String &name, cons
}
void CheckboxWidget::handleMouseUp(int x, int y, int button, int clickCount) {
- if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) {
+ if (isEnabled() && _duringPress && x >= 0 && x < _w && y >= 0 && y < _h) {
toggleState();
}
+ _duringPress = false;
}
void CheckboxWidget::setState(bool state) {
@@ -475,7 +497,7 @@ void CheckboxWidget::setState(bool state) {
}
void CheckboxWidget::drawWidget() {
- g_gui.theme()->drawCheckbox(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, Widget::_state);
+ g_gui.theme()->drawCheckboxClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _label, _state, Widget::_state);
}
#pragma mark -
@@ -523,9 +545,10 @@ RadiobuttonWidget::RadiobuttonWidget(GuiObject *boss, const Common::String &name
}
void RadiobuttonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
- if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) {
+ if (isEnabled() && _duringPress && x >= 0 && x < _w && y >= 0 && y < _h) {
toggleState();
}
+ _duringPress = false;
}
void RadiobuttonWidget::setState(bool state, bool setGroup) {
@@ -543,21 +566,21 @@ void RadiobuttonWidget::setState(bool state, bool setGroup) {
}
void RadiobuttonWidget::drawWidget() {
- g_gui.theme()->drawRadiobutton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, Widget::_state);
+ g_gui.theme()->drawRadiobuttonClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _label, _state, Widget::_state);
}
#pragma mark -
SliderWidget::SliderWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip, uint32 cmd)
: Widget(boss, x, y, w, h, tooltip), CommandSender(boss),
- _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false) {
+ _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false), _labelWidth(0) {
setFlags(WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG);
_type = kSliderWidget;
}
SliderWidget::SliderWidget(GuiObject *boss, const Common::String &name, const char *tooltip, uint32 cmd)
: Widget(boss, name, tooltip), CommandSender(boss),
- _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false) {
+ _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false), _labelWidth(0) {
setFlags(WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG);
_type = kSliderWidget;
}
@@ -611,7 +634,7 @@ void SliderWidget::handleMouseWheel(int x, int y, int direction) {
}
void SliderWidget::drawWidget() {
- g_gui.theme()->drawSlider(Common::Rect(_x, _y, _x + _w, _y + _h), valueToBarWidth(_value), _state);
+ g_gui.theme()->drawSliderClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), valueToBarWidth(_value), _state);
}
int SliderWidget::valueToBarWidth(int value) {
@@ -688,7 +711,7 @@ void GraphicsWidget::drawWidget() {
const int x = _x + (_w - _gfx.w) / 2;
const int y = _y + (_h - _gfx.h) / 2;
- g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency);
+ g_gui.theme()->drawSurfaceClip(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), getBossClipRect(), _gfx, _state, _alpha, _transparency);
}
}
@@ -725,7 +748,7 @@ void ContainerWidget::removeWidget(Widget *widget) {
}
void ContainerWidget::drawWidget() {
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorder);
+ g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder);
}
} // End of namespace GUI
diff --git a/gui/widget.h b/gui/widget.h
index 9891f32b36..0f4b300233 100644
--- a/gui/widget.h
+++ b/gui/widget.h
@@ -68,7 +68,8 @@ enum {
kPopUpWidget = 'POPU',
kTabWidget = 'TABW',
kGraphicsWidget = 'GFXW',
- kContainerWidget = 'CTNR'
+ kContainerWidget = 'CTNR',
+ kScrollContainerWidget = 'SCTR'
};
enum {
@@ -111,6 +112,7 @@ public:
virtual int16 getAbsX() const { return _x + _boss->getChildX(); }
virtual int16 getAbsY() const { return _y + _boss->getChildY(); }
+ virtual Common::Rect getBossClipRect() const;
virtual void setPos(int x, int y) { _x = x; _y = y; }
virtual void setSize(int w, int h) { _w = w; _h = h; }
@@ -168,9 +170,10 @@ class StaticTextWidget : public Widget {
protected:
Common::String _label;
Graphics::TextAlign _align;
+ ThemeEngine::FontStyle _font;
public:
- StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip = 0);
- StaticTextWidget(GuiObject *boss, const Common::String &name, const Common::String &text, const char *tooltip = 0);
+ StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip = 0, ThemeEngine::FontStyle font = ThemeEngine::kFontStyleBold);
+ StaticTextWidget(GuiObject *boss, const Common::String &name, const Common::String &text, const char *tooltip = 0, ThemeEngine::FontStyle font = ThemeEngine::kFontStyleBold);
void setValue(int value);
void setLabel(const Common::String &label);
const Common::String &getLabel() const { return _label; }
@@ -198,19 +201,15 @@ public:
void handleMouseUp(int x, int y, int button, int clickCount);
void handleMouseDown(int x, int y, int button, int clickCount);
- void handleMouseEntered(int button) { setFlags(WIDGET_HILITED); draw(); }
+ void handleMouseEntered(int button) { if (_duringPress) { setFlags(WIDGET_PRESSED); } else { setFlags(WIDGET_HILITED); } draw(); }
void handleMouseLeft(int button) { clearFlags(WIDGET_HILITED | WIDGET_PRESSED); draw(); }
- void handleTickle();
void setHighLighted(bool enable);
void setPressedState();
- void startAnimatePressedState();
- void stopAnimatePressedState();
-
- void lostFocusWidget() { stopAnimatePressedState(); }
+ void setUnpressedState();
protected:
void drawWidget();
- void wantTickle(bool tickled);
+ bool _duringPress;
private:
uint32 _lastTime;
};
diff --git a/gui/widgets/editable.cpp b/gui/widgets/editable.cpp
index 2d929113b1..4f7e584c14 100644
--- a/gui/widgets/editable.cpp
+++ b/gui/widgets/editable.cpp
@@ -274,7 +274,7 @@ void EditableWidget::drawCaret(bool erase) {
x += getAbsX();
y += getAbsY();
- g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height()), erase);
+ g_gui.theme()->drawCaretClip(Common::Rect(x, y, x + 1, y + editRect.height()), getBossClipRect(), erase);
if (erase) {
GUI::EditableWidget::String character;
@@ -303,7 +303,7 @@ void EditableWidget::drawCaret(bool erase) {
// possible glitches due to different methods used.
width = MIN(editRect.width() - caretOffset, width);
if (width > 0) {
- g_gui.theme()->drawText(Common::Rect(x, y, x + width, y + editRect.height()), character, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
+ g_gui.theme()->drawTextClip(Common::Rect(x, y, x + width, y + editRect.height()), getBossClipRect(), character, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
}
}
diff --git a/gui/widgets/edittext.cpp b/gui/widgets/edittext.cpp
index 1481bebae3..0a8725ac9e 100644
--- a/gui/widgets/edittext.cpp
+++ b/gui/widgets/edittext.cpp
@@ -36,6 +36,8 @@ EditTextWidget::EditTextWidget(GuiObject *boss, int x, int y, int w, int h, cons
setEditString(text);
setFontStyle(ThemeEngine::kFontStyleNormal);
+
+ _leftPadding = _rightPadding = 0;
}
EditTextWidget::EditTextWidget(GuiObject *boss, const String &name, const String &text, const char *tooltip, uint32 cmd, uint32 finishCmd)
@@ -46,6 +48,8 @@ EditTextWidget::EditTextWidget(GuiObject *boss, const String &name, const String
setEditString(text);
setFontStyle(ThemeEngine::kFontStyleNormal);
+
+ _leftPadding = _rightPadding = 0;
}
void EditTextWidget::setEditString(const String &str) {
@@ -93,7 +97,7 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
}
void EditTextWidget::drawWidget() {
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, ThemeEngine::kWidgetBackgroundEditText);
+ g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundEditText);
// Draw the text
adjustOffset();
@@ -101,7 +105,7 @@ void EditTextWidget::drawWidget() {
const Common::Rect &r = Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 8, _y + _h);
setTextDrawableArea(r);
- g_gui.theme()->drawText(Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 2, _y + _h), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
+ g_gui.theme()->drawTextClip(Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 2, _y + _h), getBossClipRect(), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea);
}
Common::Rect EditTextWidget::getEditRect() const {
diff --git a/gui/widgets/list.cpp b/gui/widgets/list.cpp
index 4b69202fdc..f6e5c67510 100644
--- a/gui/widgets/list.cpp
+++ b/gui/widgets/list.cpp
@@ -488,7 +488,7 @@ void ListWidget::drawWidget() {
Common::String buffer;
// Draw a thin frame around the list.
- g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorder);
+ g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder);
const int scrollbarW = (_scrollBar && _scrollBar->isVisible()) ? _scrollBarWidth : 0;
// Draw the list items
@@ -507,7 +507,7 @@ void ListWidget::drawWidget() {
// If in numbering mode, we first print a number prefix
if (_numberingMode != kListNumberingOff) {
buffer = Common::String::format("%2d. ", (pos + _numberingMode));
- g_gui.theme()->drawText(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2),
+ g_gui.theme()->drawTextClip(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2), getBossClipRect(),
buffer, _state, Graphics::kTextAlignLeft, inverted, _leftPadding, true);
pad = 0;
}
@@ -528,12 +528,12 @@ void ListWidget::drawWidget() {
color = _editColor;
adjustOffset();
width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW;
- g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state,
+ g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), getBossClipRect(), buffer, _state,
Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
} else {
buffer = _list[pos];
width = _w - r.left - scrollbarW;
- g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state,
+ g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), getBossClipRect(), buffer, _state,
Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
}
diff --git a/gui/widgets/popup.cpp b/gui/widgets/popup.cpp
index 6186492339..82f4112a97 100644
--- a/gui/widgets/popup.cpp
+++ b/gui/widgets/popup.cpp
@@ -71,6 +71,10 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY)
: Dialog(0, 0, 16, 16),
_popUpBoss(boss) {
+ _openTime = 0;
+ _buffer = nullptr;
+ _entriesPerColumn = 1;
+
// Copy the selection index
_selection = _popUpBoss->_selectedItem;
@@ -142,8 +146,6 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY)
// Remember original mouse position
_clickX = clickX - _x;
_clickY = clickY - _y;
-
- _openTime = 0;
}
void PopUpDialog::drawDialog() {
@@ -362,8 +364,11 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) {
// Draw a separator
g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x+w, y+kLineHeight));
} else {
- g_gui.theme()->drawText(Common::Rect(x+1, y+2, x+w, y+2+kLineHeight), name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled,
- Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, _leftPadding);
+ g_gui.theme()->drawText(
+ Common::Rect(x+1, y+2, x+w, y+2+kLineHeight),
+ name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled,
+ Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, _leftPadding
+ );
}
}
@@ -380,6 +385,17 @@ PopUpWidget::PopUpWidget(GuiObject *boss, const String &name, const char *toolti
_type = kPopUpWidget;
_selectedItem = -1;
+ _leftPadding = _rightPadding = 0;
+}
+
+PopUpWidget::PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip)
+ : Widget(boss, x, y, w, h, tooltip), CommandSender(boss) {
+ setFlags(WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_IGNORE_DRAG);
+ _type = kPopUpWidget;
+
+ _selectedItem = -1;
+
+ _leftPadding = _rightPadding = 0;
}
void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount) {
@@ -457,7 +473,10 @@ void PopUpWidget::drawWidget() {
Common::String sel;
if (_selectedItem >= 0)
sel = _entries[_selectedItem].name;
- g_gui.theme()->drawPopUpWidget(Common::Rect(_x, _y, _x + _w, _y + _h), sel, _leftPadding, _state, Graphics::kTextAlignLeft);
+ g_gui.theme()->drawPopUpWidgetClip(
+ Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(),
+ sel, _leftPadding, _state, Graphics::kTextAlignLeft
+ );
}
} // End of namespace GUI
diff --git a/gui/widgets/popup.h b/gui/widgets/popup.h
index 102c7fd258..37ddc276ad 100644
--- a/gui/widgets/popup.h
+++ b/gui/widgets/popup.h
@@ -58,6 +58,7 @@ protected:
public:
PopUpWidget(GuiObject *boss, const String &name, const char *tooltip = 0);
+ PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip = 0);
void handleMouseDown(int x, int y, int button, int clickCount);
void handleMouseWheel(int x, int y, int direction);
diff --git a/gui/widgets/scrollbar.cpp b/gui/widgets/scrollbar.cpp
index f1306b9c4a..d8bcb18336 100644
--- a/gui/widgets/scrollbar.cpp
+++ b/gui/widgets/scrollbar.cpp
@@ -26,6 +26,7 @@
#include "gui/widgets/scrollbar.h"
#include "gui/gui-manager.h"
#include "gui/ThemeEngine.h"
+#include "gui/widgets/scrollcontainer.h"
namespace GUI {
@@ -202,7 +203,11 @@ void ScrollBarWidget::drawWidget() {
state = ThemeEngine::kScrollbarStateSlider;
}
- g_gui.theme()->drawScrollbar(Common::Rect(_x, _y, _x+_w, _y+_h), _sliderPos, _sliderHeight, state, _state);
+ Common::Rect clipRect = getBossClipRect();
+ //scrollbar is not a usual child of ScrollContainerWidget, so it gets this special treatment
+ if (dynamic_cast<ScrollContainerWidget *>(_boss))
+ clipRect.right += _w;
+ g_gui.theme()->drawScrollbarClip(Common::Rect(_x, _y, _x+_w, _y+_h), clipRect, _sliderPos, _sliderHeight, state, _state);
}
} // End of namespace GUI
diff --git a/gui/widgets/scrollcontainer.cpp b/gui/widgets/scrollcontainer.cpp
new file mode 100644
index 0000000000..1b38478c11
--- /dev/null
+++ b/gui/widgets/scrollcontainer.cpp
@@ -0,0 +1,147 @@
+/* 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.
+ *
+ */
+
+#include "common/util.h"
+#include "gui/widgets/scrollcontainer.h"
+#include "gui/gui-manager.h"
+
+#include "gui/ThemeEval.h"
+
+namespace GUI {
+
+ScrollContainerWidget::ScrollContainerWidget(GuiObject *boss, int x, int y, int w, int h)
+ : Widget(boss, x, y, w, h) {
+ init();
+}
+
+ScrollContainerWidget::ScrollContainerWidget(GuiObject *boss, const Common::String &name)
+ : Widget(boss, name) {
+ init();
+}
+
+void ScrollContainerWidget::init() {
+ setFlags(WIDGET_ENABLED);
+ _type = kScrollContainerWidget;
+ _verticalScroll = new ScrollBarWidget(this, _w-16, 0, 16, _h);
+ _verticalScroll->setTarget(this);
+ _scrolledX = 0;
+ _scrolledY = 0;
+ _limitH = 140;
+ recalc();
+}
+
+void ScrollContainerWidget::recalc() {
+ int scrollbarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
+ _limitH = _h;
+
+ //calculate virtual height
+ const int spacing = g_gui.xmlEval()->getVar("Global.Font.Height", 16); //on the bottom
+ int h = 0;
+ int min = spacing, max = 0;
+ Widget *ptr = _firstWidget;
+ while (ptr) {
+ if (ptr != _verticalScroll) {
+ int y = ptr->getAbsY() - getChildY();
+ min = MIN(min, y - spacing);
+ max = MAX(max, y + ptr->getHeight() + spacing);
+ }
+ ptr = ptr->next();
+ }
+ h = max - min;
+
+ _verticalScroll->_numEntries = h;
+ _verticalScroll->_currentPos = _scrolledY;
+ _verticalScroll->_entriesPerPage = _limitH;
+ _verticalScroll->setPos(_w - scrollbarWidth, _scrolledY+1);
+ _verticalScroll->setSize(scrollbarWidth, _limitH -2);
+}
+
+
+ScrollContainerWidget::~ScrollContainerWidget() {}
+
+int16 ScrollContainerWidget::getChildX() const {
+ return getAbsX() - _scrolledX;
+}
+
+int16 ScrollContainerWidget::getChildY() const {
+ return getAbsY() - _scrolledY;
+}
+
+uint16 ScrollContainerWidget::getWidth() const {
+ return _w - (_verticalScroll->isVisible() ? _verticalScroll->getWidth() : 0);
+}
+
+uint16 ScrollContainerWidget::getHeight() const {
+ return _limitH;
+}
+
+void ScrollContainerWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ Widget::handleCommand(sender, cmd, data);
+ switch (cmd) {
+ case kSetPositionCmd:
+ _scrolledY = _verticalScroll->_currentPos;
+ reflowLayout();
+ draw();
+ g_gui.doFullRedraw();
+ break;
+ }
+}
+
+void ScrollContainerWidget::reflowLayout() {
+ Widget::reflowLayout();
+
+ //reflow layout of inner widgets
+ Widget *ptr = _firstWidget;
+ while (ptr) {
+ ptr->reflowLayout();
+ ptr = ptr->next();
+ }
+
+ //recalculate height
+ recalc();
+
+ //hide those widgets which are out of visible area
+ ptr = _firstWidget;
+ while (ptr) {
+ int y = ptr->getAbsY() - getChildY();
+ int h = ptr->getHeight();
+ bool visible = true;
+ if (y + h - _scrolledY < 0) visible = false;
+ if (y - _scrolledY > _limitH) visible = false;
+ ptr->setVisible(visible);
+ ptr = ptr->next();
+ }
+
+ _verticalScroll->setVisible(_verticalScroll->_numEntries > _limitH); //show when there is something to scroll
+}
+
+void ScrollContainerWidget::drawWidget() {
+ g_gui.theme()->drawDialogBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + getHeight() - 1), getBossClipRect(), ThemeEngine::kDialogBackgroundDefault);
+}
+
+Widget *ScrollContainerWidget::findWidget(int x, int y) {
+ if (_verticalScroll->isVisible() && x >= _w - _verticalScroll->getWidth())
+ return _verticalScroll;
+ return Widget::findWidgetInChain(_firstWidget, x + _scrolledX, y + _scrolledY);
+}
+
+} // End of namespace GUI
diff --git a/gui/widgets/scrollcontainer.h b/gui/widgets/scrollcontainer.h
new file mode 100644
index 0000000000..692c7e3507
--- /dev/null
+++ b/gui/widgets/scrollcontainer.h
@@ -0,0 +1,63 @@
+/* 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.
+ *
+ */
+
+#ifndef GUI_WIDGETS_SCROLLCONTAINER_H
+#define GUI_WIDGETS_SCROLLCONTAINER_H
+
+#include "gui/widget.h"
+#include "common/str.h"
+#include "scrollbar.h"
+
+namespace GUI {
+
+class ScrollContainerWidget: public Widget {
+ ScrollBarWidget *_verticalScroll;
+ int16 _scrolledX, _scrolledY;
+ uint16 _limitH;
+
+ void recalc();
+
+public:
+ ScrollContainerWidget(GuiObject *boss, int x, int y, int w, int h);
+ ScrollContainerWidget(GuiObject *boss, const Common::String &name);
+ ~ScrollContainerWidget();
+
+ void init();
+ virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
+ virtual void reflowLayout();
+
+protected:
+ // We overload getChildY to make sure child widgets are positioned correctly.
+ // Essentially this compensates for the space taken up by the tab title header.
+ virtual int16 getChildX() const;
+ virtual int16 getChildY() const;
+ virtual uint16 getWidth() const;
+ virtual uint16 getHeight() const;
+
+ virtual void drawWidget();
+
+ virtual Widget *findWidget(int x, int y);
+};
+
+} // End of namespace GUI
+
+#endif
diff --git a/gui/widgets/tab.cpp b/gui/widgets/tab.cpp
index 756781a04b..15e6a9d370 100644
--- a/gui/widgets/tab.cpp
+++ b/gui/widgets/tab.cpp
@@ -80,9 +80,19 @@ TabWidget::~TabWidget() {
}
int16 TabWidget::getChildY() const {
+ // NOTE: if you change that, make sure to do the same
+ // changes in the ThemeLayoutTabWidget (gui/ThemeLayout.cpp)
return getAbsY() + _tabHeight;
}
+uint16 TabWidget::getHeight() const {
+ // NOTE: if you change that, make sure to do the same
+ // changes in the ThemeLayoutTabWidget (gui/ThemeLayout.cpp)
+ // NOTE: this height is used for clipping, so it *includes*
+ // tabs, because it starts from getAbsY(), not getChildY()
+ return _h + _tabHeight;
+}
+
int TabWidget::addTab(const String &title) {
// Add a new tab page
Tab newTab;
@@ -258,6 +268,12 @@ void TabWidget::adjustTabs(int value) {
void TabWidget::reflowLayout() {
Widget::reflowLayout();
+ // NOTE: if you change that, make sure to do the same
+ // changes in the ThemeLayoutTabWidget (gui/ThemeLayout.cpp)
+ _tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height");
+ _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
+ _titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top");
+
for (uint i = 0; i < _tabs.size(); ++i) {
Widget *w = _tabs[i].firstWidget;
while (w) {
@@ -266,10 +282,6 @@ void TabWidget::reflowLayout() {
}
}
- _tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height");
- _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
- _titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top");
-
if (_tabWidth == 0) {
_tabWidth = 40;
#ifdef __DS__
@@ -304,9 +316,9 @@ void TabWidget::drawWidget() {
for (int i = _firstVisibleTab; i < (int)_tabs.size(); ++i) {
tabs.push_back(_tabs[i].title);
}
- g_gui.theme()->drawDialogBackground(Common::Rect(_x + _bodyLP, _y + _bodyTP, _x+_w-_bodyRP, _y+_h-_bodyBP), _bodyBackgroundType);
+ g_gui.theme()->drawDialogBackgroundClip(Common::Rect(_x + _bodyLP, _y + _bodyTP, _x+_w-_bodyRP, _y+_h-_bodyBP+_tabHeight), getBossClipRect(), _bodyBackgroundType);
- g_gui.theme()->drawTab(Common::Rect(_x, _y, _x+_w, _y+_h), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad);
+ g_gui.theme()->drawTabClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad);
}
void TabWidget::draw() {
diff --git a/gui/widgets/tab.h b/gui/widgets/tab.h
index 148f164fbb..17b85986b5 100644
--- a/gui/widgets/tab.h
+++ b/gui/widgets/tab.h
@@ -110,6 +110,7 @@ protected:
// We overload getChildY to make sure child widgets are positioned correctly.
// Essentially this compensates for the space taken up by the tab title header.
virtual int16 getChildY() const;
+ virtual uint16 getHeight() const;
virtual void drawWidget();
diff --git a/image/codecs/bmp_raw.cpp b/image/codecs/bmp_raw.cpp
index 83aedc84e6..68d70f25f6 100644
--- a/image/codecs/bmp_raw.cpp
+++ b/image/codecs/bmp_raw.cpp
@@ -46,9 +46,47 @@ const Graphics::Surface *BitmapRawDecoder::decodeFrame(Common::SeekableReadStrea
_surface->create(_width, _height, format);
int srcPitch = _width * (_bitsPerPixel >> 3);
- const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0;
+ int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0;
- if (_bitsPerPixel == 8) {
+ if (_bitsPerPixel == 1) {
+ srcPitch = (_width + 7) / 8;
+ extraDataLength = (srcPitch % 2) ? 2 - (srcPitch % 2) : 0;
+ }
+
+ if (_bitsPerPixel == 1) {
+ for (int i = 0; i < _height; i++) {
+ byte *dst = (byte *)_surface->getBasePtr(0, i);
+ for (int j = 0; j != _width;) {
+ byte color = stream.readByte();
+ for (int k = 0; k < 8; k++) {
+ *dst++ = (color & 0x80) ? 0x0f : 0x00;
+ color <<= 1;
+ j++;
+ if (j == _width) {
+ break;
+ }
+ }
+ }
+ stream.skip(extraDataLength);
+ }
+ } else if (_bitsPerPixel == 4) {
+ for (int i = 0; i < _height; i++) {
+ byte *dst = (byte *)_surface->getBasePtr(0, _height - i - 1);
+ for (int j = 0; j < _width; j++) {
+ byte color = stream.readByte();
+
+ *dst++ = (color & 0xf0) >> 4;
+ j++;
+
+ if (j ==_width)
+ break;
+
+ *dst++ = color & 0x0f;
+ }
+
+ stream.skip(extraDataLength);
+ }
+ } else if (_bitsPerPixel == 8) {
byte *dst = (byte *)_surface->getPixels();
for (int i = 0; i < _height; i++) {
@@ -100,6 +138,8 @@ const Graphics::Surface *BitmapRawDecoder::decodeFrame(Common::SeekableReadStrea
Graphics::PixelFormat BitmapRawDecoder::getPixelFormat() const {
switch (_bitsPerPixel) {
+ case 1:
+ case 4:
case 8:
return Graphics::PixelFormat::createFormatCLUT8();
case 24:
diff --git a/image/codecs/cinepak.cpp b/image/codecs/cinepak.cpp
index 4e858921ee..2b02fc8127 100644
--- a/image/codecs/cinepak.cpp
+++ b/image/codecs/cinepak.cpp
@@ -260,7 +260,7 @@ private:
}
static inline byte getRGBLookupEntry(const byte *colorMap, uint16 index) {
- return colorMap[s_defaultPaletteLookup[CLIP<int>(index, 0, 1024)]];
+ return colorMap[s_defaultPaletteLookup[CLIP<int>(index, 0, 1023)]];
}
};
diff --git a/image/codecs/codec.cpp b/image/codecs/codec.cpp
index 398e9c562c..910fcc18cb 100644
--- a/image/codecs/codec.cpp
+++ b/image/codecs/codec.cpp
@@ -34,6 +34,7 @@
#include "image/codecs/mpeg.h"
#include "image/codecs/msvideo1.h"
#include "image/codecs/msrle.h"
+#include "image/codecs/msrle4.h"
#include "image/codecs/qtrle.h"
#include "image/codecs/rpza.h"
#include "image/codecs/smc.h"
@@ -198,6 +199,8 @@ Codec *createBitmapCodec(uint32 tag, int width, int height, int bitsPerPixel) {
return new BitmapRawDecoder(width, height, bitsPerPixel);
case SWAP_CONSTANT_32(1):
return new MSRLEDecoder(width, height, bitsPerPixel);
+ case SWAP_CONSTANT_32(2):
+ return new MSRLE4Decoder(width, height, bitsPerPixel);
case MKTAG('C','R','A','M'):
case MKTAG('m','s','v','c'):
case MKTAG('W','H','A','M'):
diff --git a/image/codecs/msrle4.cpp b/image/codecs/msrle4.cpp
new file mode 100644
index 0000000000..fc18af8364
--- /dev/null
+++ b/image/codecs/msrle4.cpp
@@ -0,0 +1,140 @@
+/* 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.
+ *
+ */
+
+// Based off ffmpeg's msrledec.c
+#include "common/debug.h"
+#include "image/codecs/msrle4.h"
+#include "common/stream.h"
+#include "common/textconsole.h"
+#include "common/util.h"
+namespace Image {
+
+MSRLE4Decoder::MSRLE4Decoder(uint16 width, uint16 height, byte bitsPerPixel) {
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+ _bitsPerPixel = bitsPerPixel;
+}
+
+MSRLE4Decoder::~MSRLE4Decoder() {
+ _surface->free();
+ delete _surface;
+}
+
+const Graphics::Surface *MSRLE4Decoder::decodeFrame(Common::SeekableReadStream &stream) {
+ if (_bitsPerPixel == 4) {
+ decode4(stream);
+ } else
+ error("Unhandled %d bit Microsoft RLE encoding", _bitsPerPixel);
+
+ return _surface;
+}
+
+void MSRLE4Decoder::decode4(Common::SeekableReadStream &stream) {
+ int x = 0;
+ int y = _surface->h - 1;
+
+ byte *output = (byte *)_surface->getBasePtr(x, y);
+ byte *output_end = (byte *)_surface->getBasePtr(_surface->w, y);
+
+ while (!stream.eos()) {
+ byte count = stream.readByte();
+
+ if (count == 0) {
+ byte value = stream.readByte();
+
+ if (value == 0) {
+ // End of line
+
+ x = 0;
+ y--;
+ output = (byte *)_surface->getBasePtr(x, y);
+ } else if (value == 1) {
+ // End of image
+
+ return;
+ } else if (value == 2) {
+ // Skip
+
+ count = stream.readByte();
+ value = stream.readByte();
+
+ x += count;
+ y -= value;
+
+ if (y < 0) {
+ warning("MS RLE Codec: Skip beyond picture bounds");
+ return;
+ }
+
+ output = (byte *)_surface->getBasePtr(x, y);
+
+ } else {
+ // Copy data
+
+ int odd_pixel = value & 1;
+ int rle_code = (value + 1) / 2;
+ int extra_byte = rle_code & 0x01;
+
+ if (output + value > output_end) {
+ stream.skip(rle_code + extra_byte);
+ continue;
+ }
+
+ for (int i = 0; i < rle_code; i++) {
+ byte color = stream.readByte();
+ *output++ = (color & 0xf0) >> 4;
+ if (i + 1 == rle_code && odd_pixel) {
+ break;
+ }
+ *output++ = color & 0x0f;
+ }
+
+ if (extra_byte)
+ stream.skip(1);
+
+ x += value;
+ }
+
+ } else {
+ // Run data
+
+ if (output + count > output_end)
+ continue;
+
+ byte color = stream.readByte();
+
+ for (int i = 0; i < count; i++, x++) {
+ *output++ = (color & 0xf0) >> 4;
+ i++;
+ x++;
+ if (i == count)
+ break;
+ *output++ = color & 0x0f;
+ }
+ }
+
+ }
+
+ warning("MS RLE Codec: No end-of-picture code");
+}
+
+} // End of namespace Image
diff --git a/image/codecs/msrle4.h b/image/codecs/msrle4.h
new file mode 100644
index 0000000000..26f52b651d
--- /dev/null
+++ b/image/codecs/msrle4.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.
+ *
+ */
+
+#ifndef IMAGE_CODECS_MSRLE4_H
+#define IMAGE_CODECS_MSRLE4_H
+
+#include "image/codecs/codec.h"
+
+namespace Image {
+
+/**
+ * Microsoft Run-Length Encoding decoder.
+ *
+ * Used by BMP/AVI.
+ */
+class MSRLE4Decoder : public Codec {
+public:
+ MSRLE4Decoder(uint16 width, uint16 height, byte bitsPerPixel);
+ ~MSRLE4Decoder();
+
+ const Graphics::Surface *decodeFrame(Common::SeekableReadStream &stream);
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
+
+private:
+ byte _bitsPerPixel;
+
+ Graphics::Surface *_surface;
+
+ void decode4(Common::SeekableReadStream &stream);
+};
+
+} // End of namespace Image
+
+#endif
diff --git a/image/module.mk b/image/module.mk
index fdf52ec09f..3742fb909f 100644
--- a/image/module.mk
+++ b/image/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS := \
codecs/indeo3.o \
codecs/mjpeg.o \
codecs/msrle.o \
+ codecs/msrle4.o \
codecs/msvideo1.o \
codecs/qtrle.o \
codecs/rpza.o \
diff --git a/image/pict.cpp b/image/pict.cpp
index 89f115dc90..4f4f0396bf 100644
--- a/image/pict.cpp
+++ b/image/pict.cpp
@@ -340,6 +340,8 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool withPa
uint32 lineSize = MAX<int>(width * bytesPerPixel + (8 * 2 / packBitsData.pixMap.pixelSize), packBitsData.pixMap.rowBytes);
byte *buffer = new byte[lineSize * height];
+ memset(buffer, 0, lineSize * height);
+
// Read in amount of data per row
for (uint16 i = 0; i < packBitsData.pixMap.bounds.height(); i++) {
// NOTE: Compression 0 is "default". The format in SCI games is packed when 0.
diff --git a/po/POTFILES b/po/POTFILES
index 49f3b6c372..dc4a19da2e 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -19,12 +19,14 @@ gui/recorderdialog.cpp
gui/saveload-dialog.cpp
gui/themebrowser.cpp
gui/ThemeEngine.cpp
+gui/updates-dialog.cpp
gui/widget.cpp
base/main.cpp
common/error.cpp
common/rendermode.cpp
+common/updates.cpp
engines/advancedDetector.cpp
engines/dialogs.cpp
diff --git a/po/be_BY.po b/po/be_BY.po
index 5b80dc19aa..68e7cd35bb 100644
--- a/po/be_BY.po
+++ b/po/be_BY.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
-"PO-Revision-Date: 2016-02-21 23:32+0300\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
+"PO-Revision-Date: 2016-05-22 17:05+0300\n"
"Last-Translator: Ivan Lukyanov <greencis@mail.ru>\n"
"Language-Team: Ivan Lukyanov <greencis@mail.ru>\n"
"Language: Belarusian\n"
@@ -55,15 +55,16 @@ msgstr "ÃÒÕàå"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "°ÔÜÕÝÐ"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ßÕàÐ×ÐßöáÐæì ÓíâÐ ×ÐåÐÒÐÝÝÕ?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "ÂÐÚ"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "ÁöÝãáÞöÔÐ"
msgid "Triangle"
msgstr "ÂàÞåÚãâÝÐï"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "ÀÞ×ÝÐÕ"
@@ -205,14 +206,14 @@ msgstr "ÁÚöÝãæì"
msgid "Reset all FluidSynth settings to their default values."
msgstr "ÁÚöÝãæì ÝÐÛÐÔë FluidSynth ßÐ ×ÜÐþçÐÝÝö."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -240,15 +241,15 @@ msgstr "·ÐÚàëæì"
msgid "Mouse click"
msgstr "ºÛöÚ Üëèèã"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "¿ÐÚÐ×Ðæì ÚÛÐÒöïâãàã"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "¿ÕàÐßàë×ÝÐçëæì ÚÛÐÒöèë"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "¿ÕàÐÚÛîçíÝÝÕ ÝÐ þÒÕáì íÚàÐÝ"
@@ -324,8 +325,8 @@ msgstr ""
"¼ÞÒÐ ÓãÛìÝö. ·ÜÕÝÐ ÓíâÐÙ ÝÐÛÐÔë ÝÕ ßÕàÐâÒÞàëæì àãáÚãî ÒÕàáöî ÓãÛìÝö þ "
"ÑÕÛÐàãáÚãî"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<ßÐ ×ÜÐþçÐÝÝö>"
@@ -347,11 +348,11 @@ msgstr "¿ÛÐâäÞàÜÐ:"
msgid "Engine"
msgstr "ÀãåÐÒöçÞÚ"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "³àÐäöÚÐ"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "³àä"
@@ -364,7 +365,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë ÓàÐäöÚö"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "°þÔëñ"
@@ -377,11 +378,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë ÐþÔëñ"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "³ãçÝÐáæì"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "³ãçÝÐáæì"
@@ -395,216 +396,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë ÓãçÝÐáæö"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "¿ÕàÐÚàëæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "ÈÛïåö"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "ÈÛïåö"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "ÈÛïå ÔÐ ÓãÛìÝö:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "ÈÛïå ÔÐ ÓãÛìÝö:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "´ÐÔ. èÛïå:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "¿ÐÚÐ×ÒÐÕ èÛïå ÔÐ ÔÐÔÐâÚÞÒëå äÐÙÛÐþ, ÔÐÔ×ÕÝëå ÔÛï ÓãÛìÝö"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "´ÐÔ. èÛïå:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "·ÐåÐÒÐÝÝö ÓãÛìÝïþ:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "¿ÐÚÐ×ÒÐÕ èÛïå ÔÐ ×ÐåÐÒÐÝÝïþ ÓãÛìÝö"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "·ÐåÐÒÐÝÝö ÓãÛìÝïþ:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "½Õ ×ÐÔÐÔ×ÕÝë"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "¿Ð ×ÜÐþçÐÝÝö"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "°ÑïàëæÕ SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "°ÑïàëæÕ ÔëàíÚâÞàëî × äÐÙÛÐÜö ÓãÛìÝö"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "°ÑïàëæÕ ÔÐÔÐâÚÞÒãî ÔëàíÚâÞàëî ÓãÛìÝö"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "°ÑïàëæÕ ÔëàíÚâÞàëî ÔÛï ×ÐåÐÒÐÝÝïþ"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "³íâë ID ÓãÛìÝö þÖÞ ÒëÚÐàëáâÞþÒÐÕææÐ. ºÐÛö ÛÐáÚÐ, ÐÑïàëæÕ öÝèë."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~²~ëåÐÔ"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "·ÐÒïàèëæì ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "¿àÐ ß~à~ÐÓàÐÜã..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "¿àÐ ßàÐÓàÐÜã ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~½~ÐÛÐÔë..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "·ÜïÝöæì ÓÛÐÑÐÛìÝëï ÝÐÛÐÔë ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "¿~ã~áÚ"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "·Ðßãáæöæì ÐÑàÐÝãî ÓãÛìÝî"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~·~ÐÓàã×öæì..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "·ÐÓàã×öæì ×ÐåÐÒÐÝÝÕ ÔÛï ÐÑàÐÝÐÙ ÓãÛìÝö"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~´~ÐÔÐæì ÓãÛìÝî..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "ÃâàëÜÛöÒÐÙæÕ ÚÛÐÒöèã Shift, ÚÐÑ ÔÐÔÐæì ÝÕÚÐÛìÚö ÓãÛìÝïþ"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "½~Ð~ÛÐÔë ÓãÛìÝö..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "·ÜïÝöæì ÝÐÛÐÔë ÓãÛìÝö"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "²~ë~ÔÐÛöæì ÓãÛìÝî"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "²ëÔÐÛöæì ÓãÛìÝî áÐ áßöáã. ½Õ ÒëÔÐÛïÕ ÓãÛìÝî × ÝÞáìÑöâÐ"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~´~ÐÔÐæì ÓãÛìÝî..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "½~Ð~ÛÐÔë ÓãÛìÝö..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "²~ë~ÔÐÛöæì ÓãÛìÝî"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "¿ÞèãÚ ã áßöáÕ ÓãÛìÝïþ"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "¿ÞèãÚ:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "·ÐÓàã×öæì ÓãÛìÝî:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "·ÐÓàã×öæì"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -612,39 +614,39 @@ msgstr ""
"²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ×Ðßãáæöæì ÔíâíÚâÐà ãáöå ÓãÛìÝïþ? ³íâÐ ßÐâíÝæëïÛìÝÐ ÜÞÖÐ "
"ÔÐÔÐæì ÒïÛöÚãî ÚÞÛìÚÐáæì ÓãÛìÝïþ."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÐ ÐÔÚàëæì Ð×ÝÐçÐÝãî ÔëàíÚâÞàëî!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÐ ×ÝÐÙáæö ÓãÛìÝî þ Ð×ÝÐçÐÝÐÙ ÔëàíÚâÞàëö!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "°ÑïàëæÕ ÓãÛìÝî:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÔÐÛöæì ÝÐÛÐÔë ÔÛï ÓíâÐÙ ÓãÛìÝö?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "²ë ÖÐÔÐÕæÕ ×ÐÓàã×öæì ÓãÛìÝî?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "³íâÐï ÓãÛìÝï ÝÕ ßÐÔâàëÜÛöÒÐÕ ×ÐÓàã×Úã ×ÐåÐÒÐÝÝïþ ßàÐ× ÓÐÛÞþÝÐÕ ÜÕÝî."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ÝÕ ×ÜÞÓ ×ÝÐÙáæö àãåÐÒöçÞÚ ÔÛï ×ÐßãáÚã ÐÑàÐÝÐÙ ÓãÛìÝö!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "ÈÜÐâ ÓãÛìÝïþ..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "·Ðßöá..."
@@ -687,132 +689,132 @@ msgstr "¿ÕàÐÚÛîçëææÐ þ ÓãÛìÝî"
msgid "Fast replay"
msgstr "ÅãâÚÐÕ ßàÐÙÓàÐÒÐÝÝÕ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "½öÚÞÛö"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "ÚÞÖÝëï 5 åÒöÛöÝ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "ÚÞÖÝëï 10 åÒöÛöÝ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "ÚÞÖÝëï 15 åÒöÛöÝ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "ÚÞÖÝëï 30 åÒöÛöÝ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 Ú³æ"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "½Õ ×ÐÔÐÔ×ÕÝë"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "½Õ ÐâàëÜÐÛÐáï þÖëæì ×ÜÕÝë ÝÕÚÐâÞàëå ÓàÐäöçÝëå ÝÐÛÐÔ:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "ÒöÔíÐàíÖëÜ ÝÕ ÜÞÖÐ Ñëæì ×ÜÕÝÕÝë."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "ßÞþÝÐíÚàÐÝÝë àíÖëÜ ÝÕ ÜÞÖÐ Ñëæì ×ÜÕÝÕÝë"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "àíÖëÜ ÚÐàíÚâëàÞþÚö áãÐÔÝÞáöÝ ÑÐÚÞþ ÝÕ ÜÞÖÐ Ñëæì ×ÜÕÝÕÝë"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "³àÐä. àíÖëÜ:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "ÀíÖëÜ àÐáâàã:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "ÁßÕæëïÛìÝëï àíÖëÜë àíÝÔíàëÝÓã, ßÐÔâàëÜÞþÒÐÝëï ÝÕÚÐâÞàëÜö ÓãÛìÝïÜö"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "¿ÞþÝÐíÚàÐÝÝë àíÖëÜ"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "ºÐàíÚâÐÒÐæì áãÐÔÝÞáöÝë ÑÐÚÞþ ÔÛï ÓãÛìÝïþ × ÐÔàÞ×ÝÕÝÝÕÜ 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "ÃßÐÔÐÑÐÝÐï ßàëÛÐÔÐ:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "³ãÚÐÒÐï ßàëÛÐÔÐ:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "·Ð×ÝÐçÐÕ þßÐÔÐÑÐÝãî ÓãÚÐÒãî ßàëÛÐÔã æö íÜãÛïâÐà ÓãÚÐÒÞÙ ÚÐàâë"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "·Ð×ÝÐçÐÕ ÒëåÞÔÝãî ÓãÚÐÒãî ßàëÛÐÔã æö íÜãÛïâÐà ÓãÚÐÒÞÙ ÚÐàâë"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "ÃßÐÔÐÑÐÝÐï:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "³ãÚÐÒÐï ßàëÛÐÔÐ:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "ÍÜãÛïâÐà AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "³ãÚÐÒÐï ÚÐàâÐ AdLib ÒëÚÐàëáâÞþÒÐÕææÐ ÜÝÞÓöÜö ÓãÛìÝïÜö"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "ÇÐèçëÝï ÓãÚã:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -820,68 +822,64 @@ msgstr ""
"±ÞÛìèëï ×ÝÐçíÝÝö ×ÐÔÐîæì ÛÕßèãî ïÚÐáæì ÓãÚã, ÐÔÝÐÚ ïÝë ÜÞÓãæì ÝÕ "
"ßÐÔâàëÜÛöÒÐææÐ ÒÐèÐÙ ÓãÚÐÒÞÙ ÚÐàâÐÙ"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "¿àëÛÐÔÐ GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "·Ð×ÝÐçÐÕ ÒëåÞÔÝãî ÓãÚÐÒãî ßàëÛÐÔã ÔÛï MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "½Õ ÒëÚÐàëáâÞþÒÐæì Üã×ëÚã ÔÛï General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "²ëÚÐàëáâÞþÒÐæì ßÕàèãî ÔÐáâãßÝãî ßàëÛÐÔã"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont'ë ßÐÔâàëÜÛöÒÐîææÐ ÝÕÚÐâÞàëÜö ÓãÚÐÒëÜö ÚÐàâÐÜö, FluidSynth Ôë "
"Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "·ÜÕèÐÝë àíÖëÜ AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "²ëÚÐàëáâÞþÒÐæì ö MIDI, ö AdLib ÔÛï ÓÕÝÕàÐæëö ÓãÚã"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Ã×ÜÐæÝÕÝÝÕ MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "½ÐÛÐÔë FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "½ÐÛ. MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"¿ÐÚÐ×ÒÐÕ ÓãÚÐÒãî ßàëÛÐÔã ßÐ ×ÜÐþçÐÝÝö ÔÛï ÒëÒÐÔã ÝÐ Roland MT-32/LAPC1/CM32l/"
"CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "ÁÐßàÐþÔÝë Roland MT-32 (×ÐÑÐàÐÝöæì íÜãÛïæëî GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -889,16 +887,16 @@ msgstr ""
"°Ô×ÝÐçæÕ, ÚÐÛö þ ÒÐá ßÐÔÚÛîçÐÝÐ Roland-áãÜïèçÐÛìÝÐï ÓãÚÐÒÐï ßàëÛÐÔÐ ö Òë "
"ÖÐÔÐÕæÕ ïÕ ÒëÚÐàëáâÞþÒÐæì"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "ÁÐßàÐþÔÝë Roland MT-32 (ÑÕ× íÜãÛïæëö GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "ÀíÖëÜ Roland GS (ÔÐ×ÒÞÛöæì ÜÐßöÝÓ MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -906,171 +904,187 @@ msgstr ""
"°Ô×ÝÐçæÕ, ÚÐÛö ÖÐÔÐÕæÕ ÔÐ×ÒÞÛöæì ÜÐßöÝÓ ÔÛï íÜãÛïæëö MT-32 ÝÐ ßàëÛÐÔ×Õ "
"Rolans GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "½Õ ÒëÚÐàëáâÞþÒÐæì Üã×ëÚã ÔÛï MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "ÂíÚáâ ö ÐÓãçÚÐ:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "°ÓãçÚÐ"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "ÁãÑâëâàë"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "°ÑÞÕ"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "ÅãâÚÐáæì âëâàÐþ:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "ÂíÚáâ ö ÐÓãçÚÐ:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "°Óãç"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "狄"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "°ÑÞÕ"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "¿ÐÚÐ×ÒÐæì áãÑâëâàë ö ßàÐÙÓàÐÒÐæì ÓÐÒÞàÚã"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "ÅãâÚÐáæì âëâàÐþ:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "³ãçÝ. Üã×ëÚö:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "³ãçÝ. Üã×ëÚö:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "²ëÚÛ. ãáñ"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "³ãçÝÐáæì SFX:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "³ãçÝÐáæì áßÕæëïÛìÝëå ÓãÚÐÒëå íäÕÚâÐþ"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "³ãçÝÐáæì SFX:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "³ãçÝ. ÐÓãçÚö:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "³ãçÝ. ÐÓãçÚö:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "½ÐÛÐÔë FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "ÈÛïå ÔÐ âíÜ:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "ÈÛïå ÔÐ âíÜ:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"¿ÐÚÐ×ÒÐÕ èÛïå ÔÐ ÔÐÔÐâÚÞÒëå äÐÙÛÐþ ÔÐÔ×ÕÝëå, ÒëÚÐàëáâÞþÒÐÝëå ãáöÜö ÓãÛìÝïÜö "
"ÐÑÞ ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "ÈÛïå ÔÐ ßÛÐÓöÝÐþ:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "ÈÛïå ÔÐ ßÛÐÓöÝÐþ:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "ÀÞ×ÝÐÕ"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "ÂíÜÐ"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "¼ÐÛïÒÐÛÚÐ GUI:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "°þâÐ×ÐåÐÒÐÝÝÕ:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "°þâÐ×ÐåÐÒÐÝÝÕ:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "ºÛÐÒöèë"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "¼ÞÒÐ GUI:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "¼ÞÒÐ ÓàÐäöçÝÐÓÐ öÝâíàäÕÙáã ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "¿àÐÒïàÐæì ÐÑÝÐþÛÕÝÝö:"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "ÏÚ çÐáâÐ ßàÐÒïàÐæì ÐÑÝÐþÛÕÝÝö ScummVM"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "¿àÐÒÕàëæì æïßÕà"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "²ë ßÐÒöÝÝë ßÕàÐ×Ðßãáæöæì ScummVM, ÚÐÑ ãÖëæì ×ÜÕÝë."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "½Õ ÜÐÓã ßöáÐæì ã ÐÑàÐÝãî ÔëàíÚâÞàëî. ºÐÛö ÛÐáÚÐ, Ð×ÝÐçæÕ öÝèãî."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "°ÑïàëæÕ ÔëàíÚâÞàëî ÔÛï âíÜ GUI"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "°ÑïàëæÕ ÔëàíÚâÞàëî × ÔÐÔÐâÚÞÒëÜö äÐÙÛÐÜö"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "°ÑïàëæÕ ÔëàíÚâÞàëî × ßÛÐÓöÝÐÜö"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1087,65 +1101,65 @@ msgstr "# ÝÐáâ"
msgid "add"
msgstr "ÔÐÔ"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "²ëÔÐÛöæì ×ÝÐÚ"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* »çÑ"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "¿àÐÙÓàÐæì æö ×ÐßöáÐæì ÓãÛìÝïÒë ßàÐæíá"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "²ëÔÐÛöæì"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "·ÐßöáÐæì"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "¿àÐÙÓàÐæì"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "ÀíÔÐÓÐÒÐæì"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "°þâÐà:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "½ÐâÐâÚö:"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÔÐÛöæì Óíâë ×Ðßöá?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "½ÕÒïÔÞÜë ÐþâÐà"
@@ -1209,7 +1223,7 @@ msgstr "ÁâÒÐàëæì ÝÞÒë ×Ðßöá ÓãÛìÝö"
msgid "Name: "
msgstr "½Ð×ÒÐ: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "ÃÒïÔ×öæÕ ÐßöáÐÝÝÕ áÛÞâÐ %d:"
@@ -1218,64 +1232,88 @@ msgstr "ÃÒïÔ×öæÕ ÐßöáÐÝÝÕ áÛÞâÐ %d:"
msgid "Select a Theme"
msgstr "°ÑïàëæÕ âíÜã"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "±Õ× ÓàÐäöÚö"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "±Õ× ÓàÐäöÚö"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "ÁâÐÝÔÐàâÝë àÐáâÐàë×ÐâÐà"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "ÁâÐÝÔÐàâÝë"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "ÀÐáâÐàë×ÐâÐà áÐ ×ÓÛÐÔÖÒÐÝÝÕÜ"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "ÁÐ ×ÓÛÐÔÖÒÐÝÝÕÜ"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM áâÐþ ßÐÔâàëÜÛöÒÐæì ÐþâÐÜÐâëçÝãî ßàÐÒÕàÚã\n"
+"ÐÑÝÐþÛÕÝÝïþ, ïÚÐï ßÐâàÐÑãÕ ÔÞáâãßã þ ¦ÝâíàÝíâ.\n"
+"\n"
+"Æö ÖÐÔÐÕæÕ Òë þÚÛîçëæì Óíâã Þßæëî?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(²ë ×ÐþáñÔë ÜÞÖÐæÕ þÚÛîçëæì ïÕ þ ÝÐÛÐÔÐå ÝÐ ×ÐÚÛÐÔæë \"ÀÞ×ÝÐÕ\")"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "°þâÐÜÐâëçÝÐ ßàÐÒïàÐæì ÐÑÝÐþÛÕÝÝö"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "¿àÐæïÓÝãæì"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "°çëáæöæì ×ÝÐçíÝÝÕ"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "ÀãåÐÒöçÞÚ ÝÕ ßÐÔâàëÜÛöÒÐÕ þ×àÞÒÕÝì ÐÔÛÐÔÚö '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "¼ÕÝî"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "¿àÐßãáæöæì"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "¿Ðþ×Ð"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "¿àÐßãáæöæì àÐÔÞÚ"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "¿ÐÜëÛÚÐ ×ÐßãáÚã ÓãÛìÝö:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "½Õ ÜÐÓã ×ÝÐÙáæö àãåÐÒöçÞÚ ÔÛï ×ÐßãáÚã ÐÑàÐÝÐÙ ÓãÛìÝö"
@@ -1370,17 +1408,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules ±ãàèâëÝÐÒë"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "ÈâÞÔ×ÕÝì"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "ÈâÞâëÔ×ÕÝì"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "ÈâÞÜÕáïæ"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<ÅöÑÝÐÕ ×ÝÐçíÝÝÕ>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "·ÔÐÕææÐ, èâÞ ÓãÛìÝï '%s' ïèçí ÝÕÒïÔÞÜÐ."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"ºÐÛö ÛÐáÚÐ, ßÕàÐÔÐÙæÕ ÝÐáâãßÝëï ÔÐÔ×ÕÝëï ÚÐÜÐÝÔ×Õ ScummVM àÐ×ÐÜ × ÝÐ×ÒÐÙ"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "ÓãÛìÝö, ïÚãî Òë áßàÐÑãÕæÕ ÔÐÔÐæì, ö Ð×ÝÐçæÕ ïÕ ÒÕàáöî, ÜÞÒã ö Ó.Ô."
@@ -1388,11 +1442,11 @@ msgstr "ÓãÛìÝö, ïÚãî Òë áßàÐÑãÕæÕ ÔÐÔÐæì, ö Ð×ÝÐçæÕ ïÕ ÒÕàáöî, ÜÞÒã ö Ó.Ô."
msgid "~R~esume"
msgstr "¿àÐæïÓ~Ý~ãæì"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "·Ð~Ó~àã×öæì"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "·Ð~ß~öáÐæì"
@@ -1417,15 +1471,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "³~Ð~ÛÞþÝÐÕ ÜÕÝî"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "·ÐåÐÒÐæì ÓãÛìÝî:"
@@ -1434,15 +1488,16 @@ msgstr "·ÐåÐÒÐæì ÓãÛìÝî:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "·ÐåÐÒÐæì"
@@ -1466,13 +1521,13 @@ msgstr ""
"×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì ÔÐÛÕÙèãî "
"ÔÐßÐÜÞÓã."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~¾~º"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~°~ÔÜÕÝÐ"
@@ -1480,23 +1535,23 @@ msgstr "~°~ÔÜÕÝÐ"
msgid "~K~eys"
msgstr "~º~ÛÐÒöèë"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "½Õ ÜÐÓã öÝöæëïÛö×ÐÒÐæì äÐàÜÐâ ÚÞÛÕàã."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "½Õ ÐâàëÜÐÛÐáï ßÕàÐÚÛîçëæì ÒöÔíÐàíÖëÜ: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "½Õ ÐâàëÜÐÛÐáï ÒëÚÐàëáâÐæì ÚÐàíÚæëî áãÐÔÝÞáöÝ ÑÐÚÞþ."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "½Õ ÜÐÓã þÖëæì ßÞþÝÐíÚàÐÝÝë àíÖëÜ."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1510,7 +1565,7 @@ msgstr ""
"ÝÐ ÖÞàáâÚö ÔëáÚ. ¿ÐÔàÐÑï×ÝÐáæö ÜÞÖÝÐ ×ÝÐÙáæö þ\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1525,7 +1580,7 @@ msgstr ""
"×'ïÒöææÐ Üã×ëÚÐ. ¿ÐÔàÐÑï×ÝÐáæö ÜÞÖÝÐ ×ÝÐÙáæö þ\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1535,7 +1590,7 @@ msgstr ""
"README ×Ð ÑÐ×ÐÒÐÙ öÝäÐàÜÐæëïÙ, Ð âÐÚáÐÜÐ öÝáâàãÚæëïÜö ßàÐ âÞÕ, ïÚ ÐâàëÜÐæì "
"ÔÐÛÕÙèãî ÔÐßÐÜÞÓã."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1545,11 +1600,11 @@ msgstr ""
"ScummVM æÐÛÚÐÜ. ÏÝÐ, åãâçíÙ ×Ð þáñ, ÝÕ ÑãÔ×Õ ßàÐæÐÒÐæì áâÐÑöÛìÝÐ, ö "
"×ÐåÐÒÐÝÝö ÓãÛìÝïþ ÜÞÓãæì ÝÕ ßàÐæÐÒÐæì ã ÑãÔãçëå ÒÕàáöïå ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Ãáñ ÐÔÝÞ ×Ðßãáæöæì"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "ÍÜãÛïâÐà AdLib"
@@ -1630,11 +1685,11 @@ msgstr "°þÔëñ FM-Towns"
msgid "PC-98 Audio"
msgstr "°þÔëñ PC-98"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "½ÐÛÐÔÖÒÐî íÜãÛïâÐà MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "ÍÜãÛïâÐà MT-32"
@@ -1666,7 +1721,7 @@ msgstr "²ë áÐßàÐþÔë ÖÐÔÐÕæÕ ÒëÙáæö?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "²ëåÐÔ"
@@ -1751,11 +1806,11 @@ msgstr "ÀíÖëÜ ÐþâÐÔàíÓã ×ÐàÐ×"
msgid "Swipe three fingers to the right to toggle."
msgstr "¿àÐÒïÔ×öæÕ âàëÜÐ ßÐÛìæÐÜö ÝÐßàÐÒÐ ÔÛï ßÕàÐÚÛîçíÝÝï."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (ÑÕ× äöÛìâàÐþ)"
@@ -1770,19 +1825,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "±Õ× ßÐÒÕÛöçíÝÝï"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ãÚÛîçÐÝÐ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "ºÐàíÚæëï áãÐÔÝÞáöÝ ÑÐÚÞþ ÒëÚÛîçÐÝÐ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "°ÚâëþÝë ÓàÐäöçÝë äöÛìâà:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "°ÚÞÝÝë àíÖëÜ"
@@ -1815,7 +1870,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~·~ÐçëÝöæì"
@@ -2307,20 +2362,38 @@ msgstr ""
"½Õ ×ÐÑãÔ×ìæÕáï ßàë×ÝÐçëæì ÚÛÐÒöèã ÔÛï Ô×ÕïÝÝï 'Hide Toolbar', ÚÐÑ ãÑÐçëæì "
"ãÒÕáì öÝÒÕÝâÐà ã ÓãÛìÝö"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "¿àÐÒïàÐî ÐÑÝÐþÛÕÝÝö..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "ÀíÖëÜ ÑÕ× ÚÞÛÕàã"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "¿ÐÚÐ×ÒÐæì àÐÔÞÚ ÐÑ'ÕÚâÐþ"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "²ëÚÐàëáâÞþÒÐæì ÐàëÓöÝÐÛìÝëï íÚàÐÝë ×Ðßöáã/çëâÐÝÝï ÓãÛìÝö"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2350,27 +2423,49 @@ msgstr ""
"ÃÚÛîçÐÕ ßÐÔâàëÜÚã Üëèë. ´Ð×ÒÐÛïÕ ÒëÚÐàëáâÞþÒÐæì Üëè ÔÛï ßÕàÐÜïèçíÝÝï ö þ "
"ÜÕÝî ÓãÛìÝö."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "²ëÚÐàëáâÞþÒÐæì èàëäâ Hercules"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+"²ëÚÐàëáâÞþÒÐÕ èàëäâ ÒëáÞÚÐÓÐ ÐÔàÞ×ÝÕÝÝï Hercules, ÚÐÛö ÔÐáâãßÝë äÐÙÛ áÐ "
+"èàëäâÐÜ."
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "¿Ðþ×Ð ßÐÔçÐá ãÒÞÔã ÚÐÜÐÝÔ"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"¿ÐÚÐ×ÒÐÕ ÐÚÝÞ × àÐÔÚÞÜ ãÒÞÔã ÚÐÜÐÝÔë ö áâÐÒöæì ÓãÛìÝî ÝÐ ßÐþ×ã (ïÚ ã SCI) "
+"×ÐÜÕáâ ãÒÞÔã þ àíÐÛìÝëÜ çÐáÕ."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Ã×ÝÐÒöæì ÓãÛìÝî:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Ã×ÝÐÒöæì"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2381,7 +2476,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2392,7 +2487,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2403,7 +2498,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "ÄÐÙÛ ×ÐáâÐþÚö '%s' ÝÕ ×ÝÞÙÔ×ÕÝë!"
@@ -2433,20 +2528,20 @@ msgstr ""
"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÒÕáæö öå ã ÝÞÒë äÐàÜÐâ ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã "
"ÓíâÐ ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ×ÝÞþ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "²ëÚÐàëáâÞþÒÐæì àíÖëÜ ïàÚÐÙ ßÐÛöâàë"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "¼ÐÛîÕ ÓàÐäöÚã × ÒëÚÐàëáâÐÝÝÕÜ ïàÚÐÙ ßÐÛöâàë ÓãÛìÝö"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "½Õ ÐâàëÜÐÛÐáï ×ÐÓàã×öæì ×ÐåÐÒÐÝãî ÓãÛìÝî × äÐÙÛÐ."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "½Õ ÐâàëÜÐÛÐáï ×ÐåÐÒÐæì ÓãÛìÝî þ äÐÙÛ."
@@ -2463,7 +2558,7 @@ msgstr "ÅãâÚö àíÖëÜ ÒöÔíÐ"
msgid "Play movies at an increased speed"
msgstr "¿àÐÙÓàÐÒÐÕ ÒöÔíÐ ÝÐ ßÐÒïÛöçÐÝÐÙ åãâÚÐáæö"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "½Õ ÐâàëÜÐÛÐáï ×ÐåÐÒÐæì ÓãÛìÝî"
@@ -2638,49 +2733,57 @@ msgstr ""
"ÐÔÚàëæì ÐÔÛÐÔÐçÝãî ÚÐÝáÞÛì ScummVM ö þÒÕáæö ÚÐÜÐÝÔã 'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "¿àÐÙÓàÐÒÐæì àÞÛöÚ ßàÐÛñâã ÝÐÔ Myst"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr "ÀÞÛöÚ ßàÐÛñâã ÝÐÔ Myst ÝÕ ßàÐÙÓàÐÒÐþáï ÐàëÓöÝÐÛìÝëÜ àãåÐÒöçÚÞÜ."
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~À~íÖëÜ åãâÚÐÓÐ ßÕàÐåÞÔã ÐÚâëÒÐÒÐÝë"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~¿~ÕàÐåÞÔë ÐÚâëÒÐÒÐÝë"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~²~ëÚöÝãæì áâÐàÞÝÚã"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
-msgstr "¿~Ð~ÚÐ×Ðæì ÚÐàâã"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
+msgstr "¿ÐÚÐ×Ðæì ~Ú~Ðàâã"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
-msgstr "~³~ÐÛÞþÝÐÕ ÜÕÝî"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
+msgstr "³ÐÛÞþÝÐÕ ÜÕÝ~î~"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~Í~äÕÚâë ÒÐÔë þÚÛîçÐÝë"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "¿àÐßãáæöæì áæíÝë × ³ÐÛÕàíö ³öáâÞàëö"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "´Ð×ÒÐÛïÕ ÓãÛìæã ßàÐßãáæöæì ãáÕ áæíÝë þ ³ÐÛÕàíö ³öáâÞàëö"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "ÀÐáæïÓÝãæì ÝÐ þÒÕáì íÚàÐÝ ÒöÔíÐ ßàÐ áâÒÐàíÝÝÕ ÓãÛìÝö"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "ÀÐáæïÓÒÐÕ ÒöÔíÐ ßàÐ áâÒÐàíÝÝÕ ÓãÛìÝö âÐÚ, èâÞ ïÝÞ ×ÐÙÜÐÕ þÒÕáì íÚàÐÝ"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2689,23 +2792,23 @@ msgstr ""
"½Õ ÜÐÓã ×ÐåÐÒÐæì ÓãÛìÝî þ ßÐ×öæëî %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "·ÐÓàã×öæì äÐÙÛ"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "·ÐÓàãÖÐî ÓãÛìÝî..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "·ÐåÐÒÐæì äÐÙÛ"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "·ÐåÞþÒÐî ÓãÛìÝî..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2721,11 +2824,11 @@ msgstr ""
"½ÐæöáÝöæÕ ¾º, ÚÐÑ ßÕàÐÝÐ×ÒÐæì öå ×ÐàÐ×, ã ÐÔÒÐàÞâÝëÜ ÒëßÐÔÚã ÓíâÐÕ Ö "
"ßÐÒÕÔÐÜÛÕÝÝÕ ×'ïÒöææÐ ßàë ÝÐáâãßÝëÜ ×ÐßãáÚã ÓãÛìÝö.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM ßÐáßïåÞÒÐ ßÕàÐþâÒÐàëþ ãáÕ ÒÐèë ×ÐåÐÒÐÝÝö ÓãÛìÝïþ."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2781,37 +2884,46 @@ msgstr "°ÛìâíàÝÐâëþÝë þáâãß"
msgid "Use an alternative game intro (CD version only)"
msgstr "²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë þáâãß (âÞÛìÚö ÔÛï CD-ÒÕàáöö ÓãÛìÝö)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "½Õ àÐÑöæì ÐßàÐÚáöÜÐæëî ÚÞÛÕàÐþ EGA (ßÞþÝÐÚÐÛïàÞÒëï äÞÝë)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"¿àÐßãáÚÐÕ ßàÐåÞÔ ÐßàÐÚáöÜÐæëö ÚÞÛÕàÐþ EGA, ÓàÐäöÚÐ ÑãÔ×Õ ßÐÚÐ×ÐÝÐ × ãáöÜö "
"ÚÞÛÕàÐÜö"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "ÃÚÛîçëæì ÐÔÛîáâàÐÒÐÝÝÕ ÓàÐäöÚö ÒëáÞÚÐÓÐ ÐÔàÞ×ÝÕÝÝï"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "ÃÚÛîçëæì ÓàÐäöÚã ö ÚÐÝâíÝâ ÒëáÞÚÐÓÐ ÐÔàÞ×ÝÕÝÝï"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "ÃÚÛîçëæì àíÖëÜ Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "°ÔÔÐÒÐæì ßÕàÐÒÐÓã ÛöçÑÐÒëÜ ÓãÚÐÒëÜ íäÕÚâÐÜ"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "°ÔÔÐÒÐæì ßÕàÐÒÐÓã ÛöçÑÐÒëÜ ÓãÚÐÒëÜ íäÕÚâÐÜ ×ÐÜÕáâ áöÝâí×ÐÒÐÝëå"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "²ëÚÐàëáâÞþÒÐæì IMF/Yamaha FB-01 ÔÛï ÒëÒÐÔã MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2819,150 +2931,158 @@ msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒãî ÚÐàâã IBM Music Feature æö ÜÞÔãÛì áöÝâí×ã Yamaha "
"FB-01 FM ÔÛï MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "²ëÚÐàëáâÞþÒÐæì CD-ÐþÔëñ"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÓãÚÐÒëï ÔÐàÞÖÚö × CD ×ÐÜÕáâ Üã×ëÚö × äÐÙÛÐþ ÓãÛìÝö (ÚÐÛö "
"ÔÐáâãßÝÐ)"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "²ëÚÐàëáâÞþÒÐæì ÚãàáÞàë Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÚãàáÞàë Windows (ÜÕÝèëï ßÐ ßÐÜÕàë ö ÐÔÝÐÚÐÛïàÞÒëï) ×ÐÜÕáâ "
"ÚãàáÞàÐþ DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "²ëÚÐàëáâÞþÒÐæì áàíÑÝëï ÚãàáÞàë"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"²ëÚÐàëáâÞþÒÐæì ÐÛìâíàÝÐâëþÝë ÝÐÑÞà áàíÑÝëå ÚãàáÞàÐþ ×ÐÜÕáâ ×ÒëçÐÙÝëå ×ÐÛÐâëå"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "¿ÐÚÐ×ÒÐæì àÐÔÞÚ ÐÑ'ÕÚâÐþ"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "¿ÐÚÐ×ÒÐæì ÝÐ×Òë ÐÑ'ÕÚâÐþ ãÝö×Õ íÚàÐÝÐ"
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "ÃáâÐþæÕ ÔëáÚ %c ö ÝÐæöáÝöæÕ ÚÛÐÒöèã, ÚÐÑ ßàÐæïÓÝãæì."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "½Õ ÐâàëÜÐÛÐáï ×ÝÐÙáæö %s, (%c%d) ½ÐæöáÝöæÕ ÚÛÐÒöèã."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "¿ÐÜëÛÚÐ çëâÐÝÝï ÔëáÚÐ %c, (%c%d) ½ÐæöáÝöæÕ ÚÛÐÒöèã."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "³ãÛìÝï áßëÝÕÝÐ. ½ÐæöáÝöæÕ ßàÐÑÕÛ, ÚÐÑ ßàÐæïÓÝãæì."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "²ë þßíþÝÕÝë, èâÞ ÖÐÔÐÕæÕ ßÐçÐæì ö×ÝÞþ? (Y/N)Y"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "²ë þßíþÝÕÝë, èâÞ ÖÐÔÐÕæÕ ÒëÙáæö? (Y/N)Y"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "³ãÛïæì"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "ÃáâÐþæÕ ÔëáÚ × ×ÐåÐÒÐÝÝïÜö"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "²ë ßÐÒöÝÝë þÒÕáæö öÜï"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "³ãÛìÝï ½µ ±Ë»° ×ÐßöáÐÝÐ (ÔëáÚ ßÞþÝë?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "³ãÛìÝï ½µ ±Ë»° ×ÐÓàãÖÐÝÐ"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "·ÐåÞþÒÐî '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "·ÐÓàãÖÐî '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "½Ð×ÐÒöæÕ ×ÐåÐÒÐÝÝÕ ÓãÛìÝö"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "°ÑïàëæÕ ÓãÛìÝî ÔÛï ×ÐÓàã×Úö"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "½Ð×ÒÐ ÓãÛìÝö)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~¿~Ðßïà"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~½~Ðáâ"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "ÂÞÛìÚö ÐÓãçÚÐ"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "°ÓãçÚÐ ö áãÑâëâàë"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "ÂÞÛìÚö áãÑâëâàë"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "°ÓãçÚÐ ö âíÚáâ"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "°ÑïàëæÕ þ×àÞÒÕÝì áÚÛÐÔÐÝÐáæö."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "·Ð ÔÐßÐÜÞÓÐÙ ×ÒïàÝöæÕáï ÔÐ öÝáâàãÚæëö Loom(TM)."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "¿àÐÚâëÚÐÝâ"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "ÍÚáßÕàâ"
@@ -3499,23 +3619,23 @@ msgstr "»ïæÕæì ÝÐßàÐÒÐ"
msgid "Fly to lower right"
msgstr "»ïæÕæì ÝÐßàÐÒÐ-þÝö×"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "¿àÐÓÞàâÚÐ áÚÞÚÐÜö þÚÛîçÐÝÐ"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "¿àÐÓÞàâÚÐ áÚÞÚÐÜö ÒëÚÛîçÐÝÐ"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "³ãçÝ. Üã×ëÚö: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "ÅãâÚÐáæì âëâàÐþ: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3524,7 +3644,7 @@ msgstr ""
"ÀíÖëÜ \"àÞÔÝÐÓÐ\" MIDI ßÐâàÐÑãÕ ÐÑÝÐþÛÕÝÝÕ Roland Upgrade ÐÔ\n"
"LucasArts, ÐÛÕ ÝÕ åÐßÐÕ %s. ¿ÕàÐÚÛîçÐîáï ÝÐ AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3707,13 +3827,24 @@ msgstr "¿ÐÚÐ×ÒÐæì ÝÐ×Òë ÐÑ'ÕÚâÐþ"
msgid "Show labels for objects on mouse hover"
msgstr "¿ÐÚÐ×ÒÐÕ ÝÐ×Òë ÐÑ'ÕÚâÐþ ßàë ÝÐÒïÔ×ÕÝÝö ÚãàáÞàÐ Üëèë"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "²ëÚÐàëáâÞþÒÐæì ÐÝÓÛöÙáÚãî ÐÓãçÚã"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+"²ëÚÐàëáâÞþÒÐæì ÐÝÓÛöÙáÚãî ÐÓãçÚã ×ÐÜÕáâ ÝïÜÕæÚÐÙ ÔÛï þáöå ÜÞþ, ÐÚàÐÜï "
+"ÝïÜÕæÚÐÙ"
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"à ÒÐá ÐÔáãâÝöçÐÕ äÐÙÛ 'teenagent.dat'. ·ÐßÐÜßãÙæÕ ïÓÞ × ÒíÑ-áÐÙâÐ ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3817,9 +3948,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "°ÚâëþÝë àíÖëÜ äöÛìâàÐ: ½ÐÙÑÛö×Úö"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "ÃÚÛîçëæì àíÖëÜ Roland GS"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "´ÞÑ. ØÓàã"
diff --git a/po/ca_ES.po b/po/ca_ES.po
index 857e7de99e..9a1ba16a6b 100644
--- a/po/ca_ES.po
+++ b/po/ca_ES.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.6.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2013-05-05 14:16+0100\n"
"Last-Translator: Jordi Vilalta Prat <jvprat@jvprat.com>\n"
"Language-Team: Catalan <scummvm-devel@lists.sf.net>\n"
@@ -52,15 +52,16 @@ msgstr "Amunt"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Cancel·la"
@@ -100,7 +101,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Realment voleu suprimir aquesta partida?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -110,7 +111,7 @@ msgid "Yes"
msgstr "Sí"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -171,7 +172,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Triangle"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Misc"
@@ -203,14 +204,14 @@ msgstr "Reset"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Retorna tots els ajustos de FluidSynth als seus valors per defecte."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -240,15 +241,15 @@ msgstr "Tanca"
msgid "Mouse click"
msgstr "Clic del ratolí"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostra el teclat"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Assigna les tecles"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Commuta la pantalla completa"
@@ -324,8 +325,8 @@ msgstr ""
"Idioma del joc. Això no convertirà la vostra versió Espanyola del joc a "
"Anglès"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<per defecte>"
@@ -347,11 +348,11 @@ msgstr "Platafor.:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Gràfics"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -364,7 +365,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Canviar les opcions de gràfics"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Àudio"
@@ -377,11 +378,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Canviar les opcions d'àudio"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volum"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volum"
@@ -395,219 +396,220 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Canviar les opcions de volum"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Fer canvis sobre les opcions globals de MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Canviar les opcions de MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Fer canvis sobre les opcions globals de MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Canviar les opcions de MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Camins"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Camins"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Camí del joc:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Camí joc:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Camí extra:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Especifica el camí de dades addicionals utilitzades pel joc"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Camí extra:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Camí de partides:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Especifica on es desaran les partides"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Partides:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Cap"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Per defecte"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Seleccioneu el fitxer SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Seleccioneu el directori amb les dades del joc"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Seleccioneu el directori addicional del joc"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Seleccioneu el directori de les partides desades"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr ""
"Aquest identificador de joc ja està en ús. Si us plau, trieu-ne un altre."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~T~anca"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Surt de ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "~Q~uant a..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Quant a ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pcions..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Canvia les opcions globals de ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~I~nicia"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Iniciant el joc seleccionat"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~C~arrega..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Carrega una partida pel joc seleccionat"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~A~fegeix Joc..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Mantingueu premut Shift per a l'Addició Massiva"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~dita Joc..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Canvia les opcions del joc"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~S~uprimeix Joc"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr ""
"Elimina un joc de la llista. Els fitxers de dades del joc es mantenen "
"intactes"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~A~fegeix Joc..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~dita Joc..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~S~uprimeix"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Cerca a la llista de jocs"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Cerca:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Carrega partida:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Carrega"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -615,41 +617,41 @@ msgstr ""
"Esteu segur que voleu executar el detector massiu de jocs? Això pot afegir "
"una gran quantitat de jocs."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM no ha pogut obrir el directori especificat!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM no ha pogut trobar cap joc al directori especificat!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Seleccioneu el joc:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Realment voleu suprimir la configuració d'aquest joc?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
#, fuzzy
msgid "Do you want to load saved game?"
msgstr "Voleu carregar o desar el joc?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Aquest joc no suporta la càrrega de partides des del llançador."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM no ha pogut trobar cap motor capaç d'executar el joc seleccionat!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Addició Massiva..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -695,132 +697,132 @@ msgstr "Commuta"
msgid "Fast replay"
msgstr "Mode ràpid"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Mai"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "cada 5 minuts"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "cada 10 minuts"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "cada 15 minuts"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "cada 30 minuts"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Cap"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "No s'han pogut aplicar alguns canvis de les opcions gràfiques:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "no s'ha pogut canviar el mode de vídeo"
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "no s'ha pogut canviar l'ajust de pantalla completa"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "no s'ha pogut canviar l'ajust de la correcció d'aspecte"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Mode gràfic:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Mode de pintat:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Modes de tramat especials suportats per alguns jocs"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Mode pantalla completa"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Correcció de la relació d'aspecte"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Corregeix la relació d'aspecte per jocs de 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Disp. preferit:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Disp. de música:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Especifica el dispositiu de so o l'emulador de tarja de so preferit"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Especifica el dispositiu de so o l'emulador de tarja de so de sortida"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Disp. preferit:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Disp. de música:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Emulador AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib s'utilitza per la música de molts jocs"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Freq. sortida:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -828,67 +830,63 @@ msgstr ""
"Valors més alts especifiquen millor qualitat de so però pot ser que la "
"vostra tarja de so no ho suporti"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Dispositiu GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr ""
"Especifica el dispositiu de so per defecte per a la sortida General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "No utilitzis música General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Utilitza el primer dispositiu disponible"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "Fitxer SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "Algunes targes de so, FluidSynth i Timidity suporten SoundFont"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Mode combinat AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Utilitza MIDI i la generació de so AdLib alhora"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Guany MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Configuració de FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Disposit. MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Especifica el dispositiu de so per defecte per a la sortida de Roland MT-32/"
"LAPC1/CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 real (desactiva l'emulació GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -896,189 +894,205 @@ msgstr ""
"Marqueu si voleu utilitzar el vostre dispositiu hardware real de so "
"compatible amb Roland connectat al vostre ordinador"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 real (sense emulació GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
#, fuzzy
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Mode Roland GS (desactiva el mapeig GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
msgstr ""
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "No utilitzis música de Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Text i Veus:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Veus"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Subtítols"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Ambdós"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Velocitat de subt.:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Text i Veus:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Veus"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Subt"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Ambdós"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Mostra els subtítols i reprodueix la veu"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Veloc. de subt.:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Volum de música:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Volum de música:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Silenciar tot"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Volum d'efectes:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volum dels sons d'efectes especials"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Volum d'efectes:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Volum de veus:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Volum de veus:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Configuració de FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Camí dels temes:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Camí temes:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Especifica el camí de les dades addicionals utilitzades per tots els jocs o "
"pel ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Camí dels connectors:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Camí de connectors:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Misc"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Pintat GUI:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Desat automàtic:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Auto-desat:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Tecles"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Idioma GUI:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Idioma de la interfície d'usuari de ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Heu de reiniciar ScummVM perquè tots els canvis tinguin efecte."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
"No es pot escriure al directori seleccionat. Si us plau, escolliu-ne un "
"altre."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Seleccioneu el directori dels temes"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Seleccioneu el directori dels fitxers extra"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Seleccioneu el directori dels connectors"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1095,68 +1109,68 @@ msgstr ""
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Suprimeix"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr ""
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Suprimeix"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
#, fuzzy
msgid "Playback"
msgstr "Jugar"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr ""
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr ""
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr ""
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
#, fuzzy
msgid "Do you really want to delete this record?"
msgstr "Realment voleu suprimir aquesta partida?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
#, fuzzy
msgid "Unknown Author"
msgstr "Error desconegut"
@@ -1221,7 +1235,7 @@ msgstr "Crea una nova partida desada"
msgid "Name: "
msgstr "Nom: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Entreu la descripció per l'espai %d:"
@@ -1230,67 +1244,88 @@ msgstr "Entreu la descripció per l'espai %d:"
msgid "Select a Theme"
msgstr "Seleccioneu un Tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX desactivats"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX desactivats"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
#, fuzzy
msgid "Standard Renderer"
msgstr "Pintat estàndard (16bpp)"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Estàndard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
#, fuzzy
msgid "Antialiased Renderer"
msgstr "Pintat amb antialias (16bpp)"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
#, fuzzy
msgid "Antialiased"
msgstr "Amb antialias (16bpp)"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Comprova les actualitzacions..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Neteja el valor"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "El motor no suporta el nivell de depuració '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menú"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Salta"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pausa"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Salta la línia"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Error al executar el joc:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "No s'ha pogut trobar cap motor capaç d'executar el joc seleccionat"
@@ -1385,17 +1420,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr ""
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Neteja el valor"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "El joc a '%s' sembla ser desconegut."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Informeu de la següent informació a l'equip de ScummVM juntament amb el"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "nom del joc que heu provat d'afegir i la seva versió/llengua/etc.:"
@@ -1403,11 +1455,11 @@ msgstr "nom del joc que heu provat d'afegir i la seva versió/llengua/etc.:"
msgid "~R~esume"
msgstr "~C~ontinua"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "C~a~rrega"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~D~esa"
@@ -1432,15 +1484,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~R~etorna al Llançador"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Desa la partida:"
@@ -1449,15 +1501,16 @@ msgstr "Desa la partida:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Desa"
@@ -1479,13 +1532,13 @@ msgstr ""
"No s'ha pogut desar la partida (%s)! Consulteu el fitxer README per a la "
"informació bàsica i les instruccions sobre com obtenir més assistència."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~D~'acord"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~C~ancel·la"
@@ -1493,23 +1546,23 @@ msgstr "~C~ancel·la"
msgid "~K~eys"
msgstr "~T~ecles"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "No s'ha pogut iniciar el format de color."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "No s'ha pogut canviar al mode de vídeo: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "No s'ha pogut aplicar la configuració de la relació d'aspecte."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "No s'ha pogut aplicar l'ajust de pantalla completa."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1523,7 +1576,7 @@ msgstr ""
"els fitxers de dades al disc dur.\n"
"Consulteu el fitxer README per a més detalls."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1537,7 +1590,7 @@ msgstr ""
"tal de poder sentir la música del joc.\n"
"Consulteu el fitxer README per a més detalls."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1546,7 +1599,7 @@ msgstr ""
"No s'ha pogut carregar la partida (%s)! Consulteu el fitxer README per a la "
"informació bàsica i les instruccions sobre com obtenir més assistència."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1556,11 +1609,11 @@ msgstr ""
"pel ScummVM. Com a tal, probablement serà inestable, i pot ser que les "
"partides que deseu no funcionin en versions futures de ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Inicia de totes maneres"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Emulador d'AdLib"
@@ -1642,11 +1695,11 @@ msgstr ""
msgid "PC-98 Audio"
msgstr "Àudio"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Iniciant l'Emulador de MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Emulador de MT-32"
@@ -1678,7 +1731,7 @@ msgstr "Estàs segur de voler sortir?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Surt"
@@ -1764,12 +1817,12 @@ msgstr ""
msgid "Swipe three fingers to the right to toggle."
msgstr ""
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
#, fuzzy
msgid "OpenGL"
msgstr "Obre"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr ""
@@ -1784,19 +1837,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (no escalat)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "S'ha activat la correcció de la relació d'aspecte"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "S'ha desactivat la correcció de la relació d'aspecte"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Filtre de gràfics actiu:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Mode de finestra"
@@ -1829,7 +1882,7 @@ msgid "Windows MIDI"
msgstr "MIDI de Windows"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~T~anca"
@@ -2322,20 +2375,38 @@ msgstr ""
"No us oblideu d'assignar una tecla a l'acció 'Ocultar la barra d'eines' per "
"veure l'inventari complet"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Comprova les actualitzacions..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Mode clic"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostra les etiquetes dels objectes"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Utilitza les pantalles originals de desat/càrrega"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2362,27 +2433,45 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr ""
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Recupera la partida:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Restaura"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2393,7 +2482,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2404,7 +2493,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2415,7 +2504,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "No s'ha trobat el fitxer d'escena '%s'!"
@@ -2447,20 +2536,20 @@ msgstr ""
"Premeu D'Acord per convertir-les ara, en cas contrari se us tornarà a "
"demanar la propera vegada que engegueu el joc.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Utilitza el mode de paleta brillant"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Mostra els gràfics utilitzant la paleta brillant del joc"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "No s'ha pogut carregar l'estat del joc del fitxer."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "No s'ha pogut desar l'estat del joc al fitxer."
@@ -2477,7 +2566,7 @@ msgstr "Velocitat ràpida de les pel·lícules"
msgid "Play movies at an increased speed"
msgstr "Reprodueix les pel·lícules a major velocitat"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "No s'ha pogut desar l'estat del joc"
@@ -2638,49 +2727,59 @@ msgid ""
"\n"
msgstr ""
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "Mode ~Z~ip activat"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~T~ransicions activades"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~D~escarta la pàgina"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~M~ostra el mapa"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~M~enú Principal"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~E~fecte de l'aigua activat"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr ""
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2689,25 +2788,25 @@ msgstr ""
"No s'ha pogut desar a l'espai %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
#, fuzzy
msgid "Load file"
msgstr "Carrega partida:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Carregant la partida..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
#, fuzzy
msgid "Save file"
msgstr "Desa la partida:"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Desant la partida..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2724,11 +2823,11 @@ msgstr ""
"Premeu D'Acord per convertir-les ara, en cas contrari se us tornarà a "
"demanar la propera vegada.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM ha convertit satisfactòriament totes les partides desades."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2784,37 +2883,46 @@ msgstr "Introducció alternativa"
msgid "Use an alternative game intro (CD version only)"
msgstr "Utilitza una introducció del joc alternativa (només per la versió CD)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
#, fuzzy
msgid "Enable high resolution graphics"
msgstr "Activa la barra gràfica dels punts d'impacte"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
#, fuzzy
msgid "Enable high resolution graphics/content"
msgstr "Activa la barra gràfica dels punts d'impacte"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Activa el Mode Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Prefereix efectes de so digitals"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Prefereix els efectes de so digitals en lloc dels sintetitzats"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Utilitza IMF/Yamaha FB-01 per la sortida MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2822,152 +2930,161 @@ msgstr ""
"Utilitza una tarja IBM Music Feature o un mòdul sintetitzador Yamaha FB-01 "
"FM per la sortida MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Utilitza l'àudio del CD"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"Utilitza l'àudio del CD en lloc de l'àudio intern del joc, si està disponible"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Utilitza els cursors de Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Utilitza els cursors de Windows (més petits i en blanc i negre) en lloc dels "
"de DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Utilitza cursors platejats"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Utilitza el conjunt alternatiu de cursors platejats, en lloc dels normals "
"daurats"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Mostra les etiquetes dels objectes"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Inseriu el disc %c i premeu un botó per continuar."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "No s'ha pogut trobar %s, (%c%d) Premeu un botó."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Error llegint el disc %c, (%c%d) Premeu un botó."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Joc pausat. Premeu ESPAI per continuar."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
#, fuzzy
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Esteu segur de voler reiniciar? (S/N)S"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
#, fuzzy
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Esteu segur de voler sortir? (S/N)S"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Jugar"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Inseriu el disc de partides desades"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Heu d'introduir un nom"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "La partida NO s'ha desat (el disc està ple?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "La partida NO s'ha desat"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Desant '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Carregant '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Anomeneu la partida DESADA"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Seleccioneu una partida per CARREGAR"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Títol del joc)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~A~nterior"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~S~egüent"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Només veus"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Veu i subtítols"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Només subtítols"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Veus i sub."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Seleccioneu el nivell de competència."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Consulteu el manual de Loom(TM) per ajuda."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Pràctica"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3505,26 +3622,26 @@ msgstr "Vola a la dreta"
msgid "Fly to lower right"
msgstr "Vola avall i a la dreta"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
#, fuzzy
msgid "Snap scroll on"
msgstr "Desplaçament suau"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
#, fuzzy
msgid "Music volume: "
msgstr "Volum de música:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
#, fuzzy
msgid "Subtitle speed: "
msgstr "Velocitat de subt.:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3533,7 +3650,7 @@ msgstr ""
"El suport de MIDI natiu requereix l'actualització Roland de LucasArts,\n"
"però no s'ha trobat %s. S'utilitzarà AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
#, fuzzy
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
@@ -3713,12 +3830,21 @@ msgstr "Mostra les etiquetes dels objectes"
msgid "Show labels for objects on mouse hover"
msgstr "Mostra etiquetes al posar el ratolí sobre els objectes"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Us falta el fitxer 'teenagent.dat'. Obteniu-lo a la pàgina de ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3825,6 +3951,3 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Mode de filtre actiu: Pròxim"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Activa el Mode Roland GS"
diff --git a/po/cs_CZ.po b/po/cs_CZ.po
index 3a308f977c..ea8ca29b99 100644
--- a/po/cs_CZ.po
+++ b/po/cs_CZ.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.7.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-03 22:59+0100\n"
"Last-Translator: Zbynìk Schwarz <zbynek.schwarz@gmail.com>\n"
"Language-Team: \n"
@@ -56,15 +56,16 @@ msgstr "Jít nahoru"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Zru¹it"
@@ -103,7 +104,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Opravdu chcete tento soubor pøepsat?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -113,7 +114,7 @@ msgid "Yes"
msgstr "Ano"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -174,7 +175,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Trojúhrlník"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Rùzné"
@@ -206,14 +207,14 @@ msgstr "Resetovat"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Resetovat ve¹kerá nastavení FludSynth n ajejich výchozí hodnoty."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -243,15 +244,15 @@ msgstr "Zavøít"
msgid "Mouse click"
msgstr "Kliknutí my¹í"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Zobrazit klávesnici"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Pøemapovat klávesy"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Pøepnout celou obrazovku"
@@ -325,8 +326,8 @@ msgid ""
"English"
msgstr "Jazyk hry. Toto z va¹í ©panìlské verze neudìlá Anglickou"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<výchozí>"
@@ -348,11 +349,11 @@ msgstr "Platforma:"
msgid "Engine"
msgstr "Jádro"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Obraz"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -365,7 +366,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Potlaèit globální nastavení obrazu"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Zvuk"
@@ -378,11 +379,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Potlaèit globální nastavení zvuku"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Hlasitost"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Hlasitost"
@@ -396,216 +397,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Potlaèit globální nastavení hlasitosti"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Potlaèit globální nastavení MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Potlaèit globální nastavení MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Potlaèit globální nastavení MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Potlaèit globální nastavení MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Cesty"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Cesty"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Cesta Hry:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Cesta Hry:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Dodateèná Cesta:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Stanoví cestu pro dodateèná data pou¾itá ve høe"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Dodateèná Cesta:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Cesta pro ulo¾ení:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Stanovuje, kam jsou umístìny va¹e ulo¾ené hry"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Cesta pro ulo¾ení:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "®ádné"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Výchozí"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Vybrat SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Vyberte adresáø s daty hry"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Vyberte dodateèný adresáø hry"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Vyberte adresáø pro ulo¾ené hry"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Toto ID hry je u¾ zabrané. Vyberte si, prosím, jiné."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~U~konèit"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Ukonèit ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "~O~ Programu..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "O ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~V~olby..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Zmìnit globální volby ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~pustit"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Spustit zvolenou hru"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~N~ahrát..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Nahrát ulo¾enou pozici pro zvolenou hru"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~P~øidat hru..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Podr¾te Shift pro Hromadné Pøidání"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~U~pravit Hru..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Zmìnit volby hry"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~O~dstranit Hru"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Odstranit hru ze seznamu. Herní data zùstanou zachována"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~P~øidat hru..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~U~pravit hru..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~O~dstranit hru"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Hledat v seznamu her"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Hledat:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Nahrát hru:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Nahrát"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -613,39 +615,39 @@ msgstr ""
"Opravdu chcete spustit hromadnou detekci her? Toto by mohlo potenciálnì "
"pøidat velkou spoustu her. "
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM nemohl tento adresáø otevøít!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM nemohl v zadaném adresáøi najít ¾ádnou hru!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Vybrat hru:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Opravdu chcete odstranit nastavení této hry?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Chcete naèíst ulo¾enou pozici?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Tato hra nepodporuje spou¹tìní her ze spou¹tìèe"
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM nemohl najít ¾ádné jádro schopné vybranou hru spustit!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Hromadné Pøidání..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Nahrát..."
@@ -688,132 +690,132 @@ msgstr "Pøepnout do hry"
msgid "Fast replay"
msgstr "Rychlé pøehrávání"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Nikdy"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "Ka¾dých 5 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "Ka¾dých 10 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "Ka¾dých 15 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "Ka¾dých 30 min"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "®ádné"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Nelze pou¾ít nìkteré zmìny mo¾ností grafiky:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "re¾im obrazu nemohl být zmìnìn."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "nastavení celé obrazovky nemohlo být zmìnìno"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "nastavení pomìru stran nemohlo být zmìnìno"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Re¾im obrazu:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Re¾im vykreslení:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Speciální re¾imy chvìní podporované nìkterými hrami"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Re¾im celé obrazovky"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Korekce pomìru stran"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Korigovat pomìr stran pro hry 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Prioritní Zaøízení:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Hudební zaøízení"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Stanoví prioritní zvukové zaøízení nebo emulátor zvukové karty"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Stanoví výstupní zvukové zaøízení nebo emulátor zvukové karty"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Prioritní Zaø.:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Hudební zaøízení"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emulátor"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib se pou¾ívá pro hudbu v mnoha hrách"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Výstup. frekvence:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -821,66 +823,62 @@ msgstr ""
"Vy¹¹í hodnota zpùsobí lep¹í kvalitu zvuku, ale nemusí být podporována Va¹i "
"zvukovou kartou"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM Zaøízení:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Stanoví výchozí zvukové zaøízení pro výstup General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Nepou¾ívat hudbu General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Pou¾ít první dostupné zaøízení"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont je podporován nìkterými zvukovými kartami, FluidSynth a Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Smí¹ený re¾im AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Pou¾ít obì zvukové generace MIDI a AdLib"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Zesílení MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Nastavení FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Zaøízení MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Stanoví výchozí zvukové výstupní zaøízení pro Roland MT-32/LAPC1/CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Opravdový Roland MT-32 (vypne GM emulaci)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -888,16 +886,16 @@ msgstr ""
"Za¹krtnìte, pokud chcete pou¾ít pravé hardwarové zaøízení kompatibilní s "
"Roland, pøipojené k va¹emu poèítaèi"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Opravdový Roland MT-32 (¾ádná GM emulace)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Zaøízení Roland GS (zapne mapování MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -905,169 +903,185 @@ msgstr ""
"Za¹krtnìte, pokud chcete povolit záplaty mapování umo¾òující emulovat MT-32 "
"na zaøízení Roland GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Nepou¾ívat hudbu Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Text a Øeè"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Øeè"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Titulky"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Oba"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Rychlost titulkù:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Text a Øeè:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Øeè"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Titl"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Oba"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Zobrazit titulky a pøehrávat øeè"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Rychlost titulkù"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Hlasitost hudby"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Hlasitost hudby"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Ztlumit V¹e"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Hlasitost zvukù"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Hlasitost speciálních zvukových efektù"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Hlasitost zvukù"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Hlasitost øeèi"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Hlasitost øeèi"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Nastavení FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Cesta ke Vzhledu:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Cesta ke Vzhledu:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Stanoví cestu k dodateèným datùm pou¾ívaná v¹emi hrami nebo ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Cesta k Pluginùm:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Cesta k Pluginùm:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Rùzné"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Vzhled:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI Vykreslovaè:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autoukládání:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autoukládání:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Klávesy"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Jazyk GUI"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Jazyk GUI ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Pro pou¾ití tìchto nastavení musíte restartovat ScummVM."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Do zvoleného adresáøe nelze zapisovat. Vyberte, prosím, jiný."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Vyberte adresáø pro vhledy GUI"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Vyberte adresáø pro dodateèné soubory"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Vyberte adresáø pro zásuvné moduly"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1084,65 +1098,65 @@ msgstr "# dal¹í"
msgid "add"
msgstr "pøidat"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Smazat znak"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Prediktivní"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Èísla"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Nahrávat nebo pøehrát hru"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Smazat"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Nahrát"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Pøehrát"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Upravit"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Autor:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Poznámky:"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Opravdu chcete tento záznam smazat?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Neznámý autor"
@@ -1206,7 +1220,7 @@ msgstr "Vytvoøit novou ulo¾enou hru."
msgid "Name: "
msgstr "Název:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Zadejte popis pro pozici %d:"
@@ -1215,64 +1229,85 @@ msgstr "Zadejte popis pro pozici %d:"
msgid "Select a Theme"
msgstr "Vyberte Vzhled"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX zakázáno"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX zakázáno"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standardní Vykreslovaè"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standardní"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Vykreslovaè s vyhlazenými hranami"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "S vyhlazenými hranami"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Zkontrolovat Aktualizace..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Vyèistit hodnotu"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Jádro nepodporuje úroveò ladìní '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Pøeskoèit"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pauza"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Pøeskoèit øádek"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Chyba pøi spu¹tìní hry:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Nelze nalézt ¾ádné jádro schopné vybranou hru spustit"
@@ -1367,16 +1402,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Jantarová"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Vyèistit hodnotu"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Hra v '%s' se zdá být neznámá."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Prosím nahlaste následující data týmu ScummVM spolu se jménem"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "hry, kterou jste se pokusili pøidat a její verzi/jazyk/atd.:"
@@ -1384,11 +1436,11 @@ msgstr "hry, kterou jste se pokusili pøidat a její verzi/jazyk/atd.:"
msgid "~R~esume"
msgstr "~P~okraèovat"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~N~ahrát"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~U~lo¾it"
@@ -1413,15 +1465,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~N~ávrat do Spou¹tìèe"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Ulo¾it hru:"
@@ -1430,15 +1482,16 @@ msgstr "Ulo¾it hru:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Ulo¾it"
@@ -1461,13 +1514,13 @@ msgstr ""
"Ulo¾ení stavu hry selhalo (%s)! Prosím pøeètìte si dokumentaci pro základní "
"informace a pokyny k získání dal¹í podpory."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~Z~ru¹it"
@@ -1475,23 +1528,23 @@ msgstr "~Z~ru¹it"
msgid "~K~eys"
msgstr "~K~lávesy"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Nelze zavést barevný formát."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Nelze pøepnout na re¾im obrazu: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Nelze pou¾ít nastavení pomìru stran."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Nelze pou¾ít nastavení celé obrazovky."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1505,7 +1558,7 @@ msgstr ""
"datové soubory na Vá¹ pevný disk.\n"
"Pro podrobnosti si pøeètìte README."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1519,7 +1572,7 @@ msgstr ""
"abyste mohli poslouchat hudbu ve høe.\n"
"Pro podrobnosti si pøeètìte README."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1528,7 +1581,7 @@ msgstr ""
"Naètení stavu hry selhalo (%s)! Prosím pøeètìte si dokumentaci pro základní "
"informace a pokyny k získání dal¹í podpory."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1538,11 +1591,11 @@ msgstr ""
"ScummVM. Proto je mo¾né, ¾e bude nestabilní a jakékoli ulo¾ené hry nemusí "
"fungovat v budoucích verzích ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Pøesto spustit"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib Emulátor"
@@ -1623,11 +1676,11 @@ msgstr "Zvuk FM-Towns"
msgid "PC-98 Audio"
msgstr "Zvuk PC-98"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Zavádím MT-32 Emulátor"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 Emulátor"
@@ -1659,7 +1712,7 @@ msgstr "Opravdu chcete skonèit?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Ukonèit"
@@ -1744,11 +1797,11 @@ msgstr "Re¾im automatického ta¾ení je nyní"
msgid "Swipe three fingers to the right to toggle."
msgstr "Pro zapnutí pøejeïte tøemi prsty doprava."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (bez filtrování)"
@@ -1763,19 +1816,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normální (bez zmìny velikosti)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Povolena korekce pomìru stran"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Zakázána korekce pomìru stran"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktivní grafický filtr:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Re¾im do okna"
@@ -1808,7 +1861,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~Z~avøít"
@@ -2302,20 +2355,38 @@ msgstr ""
"Nezapomeòte namapovat klávesu k èinnosti 'Skrýt Panel Nástrojù, abyste "
"vidìli celý inventáø"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Zkontrolovat Aktualizace..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Re¾im pro barvoslepé"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Zobrazit jmenovky objektù"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Pou¾ít pùvodní obrazovky naètení/ulo¾ení místo ze ScummVM"
@@ -2343,27 +2414,46 @@ msgstr ""
"Povolí podporu my¹i. Umo¾ní pou¾ít my¹ pro pohyb a pro ovládání herních "
"nabídek."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules Zelená"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Obnovit hru"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Obnovit"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2374,7 +2464,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2385,7 +2475,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2396,7 +2486,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Soubor videa '%s' nenalezen'"
@@ -2427,20 +2517,20 @@ msgstr ""
"Stisknìte OK, abyste je pøevedli teï, jinak budete po¾ádáni znovu, pøi "
"spu¹tìní této hry.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Pou¾ít re¾im jasné palety"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Zobrazit grafiku pomocí jasné palety hry"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Nelze naèíst stav hry ze souboru."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Nelze ulo¾it stav hry do souboru."
@@ -2457,7 +2547,7 @@ msgstr "Zvý¹ená rychlost videa"
msgid "Play movies at an increased speed"
msgstr "Pøehrát videa se zvý¹enou rychlostí"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Nelze ulo¾it hru."
@@ -2630,49 +2720,59 @@ msgstr ""
"ladící konzoli ScummVM a pou¾ít pøíkaz 'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~R~e¾im Svi¹tìní Aktivován"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~P~øechody zapnuty"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~Z~ahodit Stránku"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~Z~obrazit Mapu"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~H~lavní Menu"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~E~fekt Vody Zapnut"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Pøeskoèit scény v Síni záznamù"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "Umo¾òuje hráèi pøeskoèit scény v Síni záznamù"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Zvìt¹it filmy o výrobì na celou obrazovku"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Zvìt¹it filmy o výrobì tak, aby vyu¾ivaly celou obrazovku"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2681,25 +2781,25 @@ msgstr ""
"Nelze ulo¾it hru do pozice %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
#, fuzzy
msgid "Load file"
msgstr "Nahrát hru:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Nahrávání hry..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
#, fuzzy
msgid "Save file"
msgstr "Ukládání hry selhalo!"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Ukládání hry..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2715,11 +2815,11 @@ msgstr ""
"\n"
"Stisknìte OK, abyste je pøevedli teï, jinak budete po¾ádáni pøí¹tì.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM úspì¹nì pøevedl v¹echny va¹e ulo¾ené pozice. "
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2775,36 +2875,45 @@ msgstr "Alternativní úvod"
msgid "Use an alternative game intro (CD version only)"
msgstr "Pou¾ít jinou verzi úvodu (Pouze verze CD)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Pøekoèit prùchod rozkladu barev EGA (pozadí v plných barvách)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Pøeskoèit prùchod rozkladu barev EGA, obraze je zobrazen v plných barvách"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Povolit grafiku ve vysokém rozli¹ení"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Povolit grafiku/obsah ve vysokém rozli¹ení"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Zapnout re¾im Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Upøednostòovat digitální zvukové efekty"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Upøednostòovat digitální zvukové efekty pøed syntetizovanými"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Pou¾ít IMF/Yamaha FB-01 pro výstup MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2812,145 +2921,154 @@ msgstr ""
"Pou¾ít kartu IBM Music Feature nebo modul syntetizátoru Yamaha FB-01 FM pro "
"výstup MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Pou¾ít zvuky na CD"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Pou¾ít zvuky na CD místo ve høe, pokud je dostupné"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Pou¾ít kurzory Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr "Pou¾ít kurzory Windows (men¹í a èernobílé) místo kurzorù z DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Pou¾ít støíbrné kurzory"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr "Pou¾ít alternativní sadu støíbrných kurzorù místo standardních zlatých"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Zobrazit jmenovky objektù"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Vlo¾te Disk %c a Stisknìte Tlaèítko Pro Pokraèování."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Nelze Najít %s, (%c%d) Stisknìte Tlaèítko."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Chyba pøi ètení disku %c, (%c%d) Stisknìte Tlaèítko."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Hra Pozastavena. Stisknìte MEZERNÍK pro pokraèování."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Jste si jisti, ¾e chcete restartovat? (A/N)A"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Jste si jisti, ¾e chcete odejít? (A/N)A"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Hrát"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Vlo¾te herní disk pro ulo¾ení/naètení"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Musíte zadat jméno"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Hra NEBYLA ulo¾ena (plný disk?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Hra NEBYLA naètena"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Ukládám '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Naèítám '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Pojmenujte svoji ULO®ENOU hru"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Vyberte hru k NAÈTENÍ"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Název hry"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~P~øedchozí"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~D~al¹í"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Pouze Øeè"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Øeè a Titulky"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Pouze Titulky"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Øeè a Titulky"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Vyberte úroveò odbornosti."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Pro nápovìdu si pøeètìte manuál Loom(TM)."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Cvièení"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Pokroèilý"
@@ -3487,23 +3605,23 @@ msgstr "Letìt doprava"
msgid "Fly to lower right"
msgstr "Letìt doprava dolù"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Pøichycení pøi posunování zapnuto"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Pøichycení pøi posunování zapnuto"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Hlasitost hudby:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Rychlost titulkù:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3512,7 +3630,7 @@ msgstr ""
"Pøirozená podpora MIDI vy¾aduje Aktualizaci Roland od LucasArts,\n"
"ale %s chybí. Místo toho je pou¾it AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3687,12 +3805,21 @@ msgstr "Zobrazit jmenovky objektù"
msgid "Show labels for objects on mouse hover"
msgstr "Zobrazit jmenovky objektù pøi najetí my¹i"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Chybí vám soubor 'teenagent.dat'. Mù¾ete ho získat ze stránky ScummVM."
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3806,9 +3933,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktivní re¾im filtru: Nejbli¾¹í"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Zapnout re¾im Roland GS"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Pøidat Hru..."
diff --git a/po/da_DK.po b/po/da_DK.po
index 934297bd80..38bbf29ada 100644
--- a/po/da_DK.po
+++ b/po/da_DK.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-25 21:08+0100\n"
"Last-Translator: Steffen Nyeland <steffen@nyeland.dk>\n"
"Language-Team: Steffen Nyeland <steffen@nyeland.dk>\n"
@@ -54,15 +54,16 @@ msgstr "Gå op"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Fortryd"
@@ -101,7 +102,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Vil du virkelig overskrive filen?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -111,7 +112,7 @@ msgid "Yes"
msgstr "Ja"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -172,7 +173,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Triangulær"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Andet"
@@ -204,14 +205,14 @@ msgstr "Nulstil"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Nulstil alle FluidSynth indstillinger til deres standard værdier."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -241,15 +242,15 @@ msgstr "Luk"
msgid "Mouse click"
msgstr "Muse klik"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Vis tastatur"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Kortlæg taster"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Skift fuldskærm"
@@ -325,8 +326,8 @@ msgstr ""
"Spillets sprog. Dette vil ikke ændre din spanske version af spillet til "
"engelsk"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<standard>"
@@ -348,11 +349,11 @@ msgstr "Platform:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafik"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -365,7 +366,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Overstyr globale grafik indstillinger"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Lyd"
@@ -378,11 +379,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Overstyr globale lyd indstillinger"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Lydstyrke"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Lydstyrke"
@@ -396,216 +397,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Overstyr globale lydstyrke indstillinger"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Overstyr globale MIDI indstillinger"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Overstyr globale MIDI indstillinger"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Overstyr globale MT-32 indstillinger"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Overstyr globale MT-32 indstillinger"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Stier"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Stier"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Spil sti:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Spil sti:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Ekstra sti:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Angiver sti til ekstra data der bruges i spillet"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Ekstra sti:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Gemme sti:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Angiver hvor dine gemmer bliver lagt"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Gemme sti:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ingen"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Standard"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Vælg SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Vælg bibliotek med spil data"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Vælg ekstra spil bibliotek"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Vælg bibliotek til spil gemmer"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Dette spil ID er allerede i brug. Vælg venligst et andet."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~A~fslut"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Slut ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "~O~m..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Om ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~I~ndstillinger..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Ændre globale ScummVM indstillinger"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tart"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Start det valgte spil"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "Ind~l~æs..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Indlæs gemmer for det valgte spil"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~T~ilføj spil..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Hold Skift for at tilføje flere"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~R~ediger spil..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Ændre spil indstillinger"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~F~jern spil"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Fjerner spil fra listen. Spillets data filer forbliver uberørt"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~T~ilføj spil..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~R~ediger spil..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~F~jern spil"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Søg i spil liste"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Søg:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Indlæs spil:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Indlæs"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -613,40 +615,40 @@ msgstr ""
"Vil du virkelig køre fler spils detektoren? Dette kunne potentielt tilføje "
"et stort antal spil."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunne ikke åbne det angivne bibliotek!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM kunne ikke finde noget spil i det angivne bibliotek!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Vælg spillet:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Vil du virkelig fjerne denne spil konfiguration?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vil du indlæse gemmer?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Dette spil understøtter ikke indlæsning af spil fra spiloversigten."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM kunne ikke finde en motor, istand til at afvikle det valgte spil!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Tilføj flere..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Optag..."
@@ -689,132 +691,132 @@ msgstr "Skift til Spil"
msgid "Fast replay"
msgstr "Hurtig afspil"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Aldrig"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "hvert 5. minut"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "hvert 10. minut"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "hvert 15. minut"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "hvert 30. minut"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ingen"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Anvendelse af ændringer for grafiske indstillinger fejlede:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "videotilstanden kunne ikke ændres."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "fuld skærm indstillingen kunne ikke ændres"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "billedformat indstillingen ikke kunne ændres"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafik tilstand:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Rendere tilstand:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Speciel farvereduceringstilstand understøttet a nogle spil"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Fuldskærms tilstand"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Billedformat korrektion"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Korrekt billedformat til 320x200 spil"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Foretruk. enhed:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musik enhed:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Angiver foretukket lyd enhed eller lydkort emulator"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Angiver lyd udgangsenhed eller lydkorts emulator"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Foretruk. enh.:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musik enhed:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emulator:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib bliver brugt til musik i mange spil"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Udgangsfrekvens:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -822,64 +824,60 @@ msgstr ""
"Højere værdi angiver bedre lyd kvalitet, men understøttes måske ikke af dit "
"lydkort"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM enhed:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Angiver standard lyd enhed for Generel MIDI-udgang"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Brug ikke Generel MIDI musik"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Brug første tilgængelig enhed"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "SoundFont er understøttet af nogle lydkort, FluidSynth og Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Blandet AdLib/MIDI tilstand"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Brug både MIDI og AdLib lyd generering"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI lydstyrke:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth indstillinger"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 enhed:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr "Angiver standard lyd enhed for Roland MT-32/LAPC1/CM32I/CM64 udgang"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Ægte Roland MT-32 (undlad GM emulering)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -887,16 +885,16 @@ msgstr ""
"Kryds af hvis du vil bruge din rigtige hardware Roland-kompatible lyd enhed "
"tilsluttet til din computer"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Ægte Roland MT-32 (ingen GM emulering)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS enhed (aktivér MT-32 tilknytninger)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -904,169 +902,185 @@ msgstr ""
"Kryds af hvis du vil aktivere patch tilknytninger, for at emulere en MT-32 "
"på en Roland GS enhed"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Brug ikke Roland MT-32 musik"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Tekst og tale:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Tale"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Undertekster"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Begge"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Tekst hastighed:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Tekst og tale:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Tale"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Tekst"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Begge"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Vis undertekster og afspil tale"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Tekst hastighed:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musik lydstyrke:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musik lydstyrke:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Mute alle"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "SFX lydstyrke:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Lydstyrke for specielle lydeffekter"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "SFX lydstyrke:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Tale lydstyrke:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Tale lydstyrke:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth indstillinger"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Tema sti:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Tema sti:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Angiver sti til ekstra data brugt af alle spil eller ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Plugin sti:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Plugin sti:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Andet"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI renderer:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Auto gemme:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Auto gemme:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Taster"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Sprog:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Sprog for brugerfladen i ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Du skal genstarte ScummVM før dine ændringer har effekt."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Der kan ikke skrives til det valgte bibliotek. Vælg venligst et andet."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Vælg bibliotek for GUI temaer"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Vælg bibliotek for ekstra filer"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Vælg bibliotek for plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1083,65 +1097,65 @@ msgstr "# næste"
msgid "add"
msgstr "tilføj"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Slet tegn"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Præ"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Num"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Optag eller Afspil Gameplay"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Slet"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Optag"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Afspil"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Ret"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Forfatter: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Noter: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Vil du virkelig slette denne optagelse?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Ukendt forfatter"
@@ -1205,7 +1219,7 @@ msgstr "Opret en ny gemmer"
msgid "Name: "
msgstr "Navn:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Indtast en beskrivelse af plads %d:"
@@ -1214,64 +1228,85 @@ msgstr "Indtast en beskrivelse af plads %d:"
msgid "Select a Theme"
msgstr "Vælg et tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Deaktiveret GFX"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Deaktiveret GFX"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standard renderer"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Antialias renderer"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Antialias"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Søg efter opdateringer..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Slet værdi"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Motor understøtter ikke fejlfindingsniveau '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Spring over"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pause"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Spring linje over"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fejl ved kørsel af spil:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Kunne ikke finde nogen motor istand til at afvikle det valgte spil"
@@ -1366,17 +1401,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules brun"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Slet værdi"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Spillet i '%s' ser ud til at være ukendt."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Venligst, rapportere følgende data til ScummVM holdet sammen med navnet"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "på det spil, du forsøgte at tilføje og dets version/sprog/ etc.:"
@@ -1384,11 +1436,11 @@ msgstr "på det spil, du forsøgte at tilføje og dets version/sprog/ etc.:"
msgid "~R~esume"
msgstr "Gen~o~ptag"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~H~ent"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~G~em"
@@ -1413,15 +1465,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~R~etur til oversigt"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Gemmer:"
@@ -1430,15 +1482,16 @@ msgstr "Gemmer:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Gem"
@@ -1461,13 +1514,13 @@ msgstr ""
"Gem af spiltilstand fejlede (%s)! Se venligst README for grundlæggende "
"oplysninger, og for at få instruktioner om, hvordan man får yderligere hjælp."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~F~ortryd"
@@ -1475,23 +1528,23 @@ msgstr "~F~ortryd"
msgid "~K~eys"
msgstr "~T~aster"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kunne ikke initialisere farveformat."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunne ikke skifte til videotilstand: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikke anvende billedformat korrektion indstilling."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikke anvende fuldskærm indstilling."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1505,7 +1558,7 @@ msgstr ""
"datafiler til din harddisk i stedet.\n"
"Se README fil for detaljer."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1519,7 +1572,7 @@ msgstr ""
"for at lytte til spillets musik.\n"
"Se README fil for detaljer."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1529,7 +1582,7 @@ msgstr ""
"grundlæggende oplysninger, og for at få instruktioner om, hvordan man får "
"yderligere hjælp."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1539,11 +1592,11 @@ msgstr ""
"ScummVM. Således, er det sandsynligt, at det er ustabilt, og alle gemmer du "
"foretager fungerer muligvis ikke i fremtidige versioner af ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Start alligevel"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib emulator"
@@ -1623,11 +1676,11 @@ msgstr "FM Towns lyd"
msgid "PC-98 Audio"
msgstr "PC-98 lyd"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Initialisere MT-32 emulator"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 emulator"
@@ -1659,7 +1712,7 @@ msgstr "Vil du virkelig afslutte?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Afslut"
@@ -1744,11 +1797,11 @@ msgstr "Auto-træk tilstand er nu"
msgid "Swipe three fingers to the right to toggle."
msgstr "Før tre fingre til højre for at skifte."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (Ingen filtrering)"
@@ -1763,19 +1816,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (ingen skalering)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Aktivér billedformat korrektion"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Deaktivér billedformat korrektion"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktive grafik filtre:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Vindue tilstand"
@@ -1808,7 +1861,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~L~uk"
@@ -2301,20 +2354,38 @@ msgstr ""
"Glem ikke at tildele en tast til 'Skjul værktøjslinje' handling for at se "
"hele oversigten"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Søg efter opdateringer..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Farveblind-tilstand"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Vis labels på genstande"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Brug original gem/indlæs skærme"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Brug de originale gem/indlæs skærme, istedet for dem fra ScummVM"
@@ -2342,27 +2413,46 @@ msgstr ""
"Aktivér muse support. Gør det muligt at bruge musen til bevægelse og i spil "
"menuer."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules grøn"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Gendan spil:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Gendan"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2373,7 +2463,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2384,7 +2474,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2395,7 +2485,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Filmsekvens fil '%s' ikke fundet!"
@@ -2426,20 +2516,20 @@ msgstr ""
"Tryk på OK for at konvertere dem nu, ellers vil du blive spurgt igen, næste "
"gang du starter spillet.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Brug lys palet tilstand"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Vis grafik ved hjælp af spillets lyse palette"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Mislykkedes at indlæse spil tilstand fra fil."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Mislykkedes at gemme spil tilstand til fil."
@@ -2456,7 +2546,7 @@ msgstr "Hurtig film hastighed"
msgid "Play movies at an increased speed"
msgstr "Afspil film med forhøjet hastighed"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Mislykkedes at gemme spil"
@@ -2631,51 +2721,61 @@ msgstr ""
"'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ip tilstand aktiveret"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~O~vergange aktiveret"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "Smi~d~ side"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "Vi~s~ kort"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "Hoved~m~enu"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~V~andeffekter aktiveret"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Spring \"Hall of Records\" storyboard scener over"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Giver spilleren mulighed for at springe \"Hall of Records\" storyboard "
"scener over"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Skalér skabelsen af videoerne til fuld skærm"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Skalér skabelsen af videoerne, så de fylder hele skærmen"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2684,23 +2784,23 @@ msgstr ""
"Kan ikke gemme spil på plads %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Indlæs fil"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Indlæser spil..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Gem fil"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Gemmer spil..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2716,11 +2816,11 @@ msgstr ""
"\n"
"Tryk på OK for at konvertere dem nu, ellers vil du blive spurgt næste gang.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM konverterede med succes alle dine gemmer."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2776,37 +2876,46 @@ msgstr "Alternativ intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "Brug en alternativ spil intro (kun CD version)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Skip EGA farvereducering (fuldfarvet baggrunde)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Spring farvereducering i EGA spil over, grafikken bliver vist med fulde "
"farver"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Aktivér grafik i høj opløsning"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Aktivér høj opløsnings grafik/indhold"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Aktivér Roland GS tilstand"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Foretræk digitale lydeffekter"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Foretræk digitale lydeffekter i stedet for syntetiserede"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Brug IMF/Yamaha FB-01 til MIDI-udgang"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2814,146 +2923,155 @@ msgstr ""
"Bruge et IBM Musik Feature-kort eller et Yamaha FB-01 FM synth modul til "
"MIDI-udgang"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Brug CD lyd"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Brug cd-lyd i stedet for lyd fra spillet, hvis tilgængelige"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Brug Windows markør"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr "Brug Windows-markører (mindre og monokrome) i stedet for dem fra DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Brug sølv markør"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Brug det alternative sæt af sølv markører, i stedet for de normale gyldne"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Vis labels på genstande"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Indsæt Disk %c og Tryk på knappen for at fortsætte."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Kunne ikke finde %s, (%c%d) Tryk på knappen."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Fejl ved læsning af disk %c, (%c%d) Tryk på knappen."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Spil sat på pause. Tryk MELLEMRUM for at fortsætte."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Er du sikker på at du vil genstarte? (J/N)J"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Er du sikker på at du vil afslutte? (J/N)J"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Spil"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Indsæt gem/indlæs spil disk"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Du skal indtaste et name"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Spillet blev ikke gemt (disk fuld?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Spillet blev IKKE indlæst"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Gemmer '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Indlæser '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Navngiv din GEMMER"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Vælg et spil at indlæse"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Spil titel)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "Fo~r~rige"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~N~æste"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Kun tale"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tale og Undertekster"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Kun undertekster"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tale & Tekst"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Vælg et Færdighedsniveau."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Se din Loom(TM) manual for hjælp."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Træning"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3490,23 +3608,23 @@ msgstr "Flyv til højre"
msgid "Fly to lower right"
msgstr "Flyv nederst til højre"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Jævn bevægelse til"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Jævn bevægelse fra"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Musik lydstyrke: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Tekst hastighed: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3515,7 +3633,7 @@ msgstr ""
"Indbygget MIDI understøttelse kræver Roland opgradering fra LucasArts,\n"
"men %s mangler. Bruger AdLib i stedet."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3695,12 +3813,21 @@ msgstr "Vis labels på genstande"
msgid "Show labels for objects on mouse hover"
msgstr "Vis labels for genstande musen er henover"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Du mangler filen 'teenagent.dat'. Hent den på ScummVM hjemmesiden"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3798,9 +3925,6 @@ msgstr "Brug MPEG-video fra DVD-versionen, i stedet for lavere opløsning AVI"
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktiv filter tilstand: Nærmest"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktivér Roland GS tilstand"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Tilføj spil..."
diff --git a/po/de_DE.po b/po/de_DE.po
index dbfeba57d5..227204e395 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -1,23 +1,22 @@
# German translation for ScummVM.
# Copyright (C) 2010-2016 The ScummVM Team
# This file is distributed under the same license as the ScummVM package.
-# Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari <scummvm@rootfather.de>, 2016.
+# Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari <rootfather@scummvm.org>, 2016.
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.8.0git\n"
+"Project-Id-Version: ScummVM 1.9.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
-"PO-Revision-Date: 2016-02-22 20:53+0100\n"
-"Last-Translator: Simon Sawatzki <SimSaw@gmx.de>\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
+"PO-Revision-Date: 2016-07-19 9:40:00+0200\n"
+"Last-Translator: Lothar Serra Mari <rootfather@scummvm.org>\n"
"Language-Team: Simon Sawatzki <SimSaw@gmx.de>, Lothar Serra Mari "
-"<scummvm@rootfather.de>\n"
+"<rootfather@scummvm.org>\n"
"Language: Deutsch\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Poedit 1.8.5\n"
#: gui/about.cpp:94
#, c-format
@@ -56,15 +55,16 @@ msgstr "Pfad hoch"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Abbrechen"
@@ -103,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Möchten Sie diese Datei wirklich überschreiben?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -113,7 +113,7 @@ msgid "Yes"
msgstr "Ja"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -174,7 +174,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Dreieck"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Sonstiges"
@@ -200,20 +200,20 @@ msgstr "Siebenstufig"
#: gui/fluidsynth-dialog.cpp:150
msgid "Reset"
-msgstr "Rücksetzen"
+msgstr "Zurücksetzen"
#: gui/fluidsynth-dialog.cpp:150
msgid "Reset all FluidSynth settings to their default values."
msgstr "Setzt alle FluidSynth-Einstellungen auf ihre Standard-Werte zurück."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -243,15 +243,15 @@ msgstr "Schließen"
msgid "Mouse click"
msgstr "Mausklick"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Tastatur anzeigen"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Tasten neu zuweisen"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Vollbild umschalten"
@@ -327,8 +327,8 @@ msgstr ""
"Sprache des Spiels. Diese Funktion wird nicht eine spanische Version des "
"Spiels in eine deutsche verwandeln."
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<Standard>"
@@ -350,11 +350,11 @@ msgstr "Plattform:"
msgid "Engine"
msgstr "Engine"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafik"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -367,7 +367,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Globale Grafik-Einstellungen übergehen"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Audio"
@@ -380,11 +380,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Globale Audio-Einstellungen übergehen"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Lautstärke"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Lautst."
@@ -398,218 +398,219 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Globale Lautstärke-Einstellungen übergehen"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Globale MIDI-Einstellungen übergehen"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Globale MIDI-Einstellungen übergehen"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Globale MT-32-Einstellungen übergehen"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Globale MT-32-Einstellungen übergehen"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Pfade"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Pfade"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Spielpfad:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Spielpfad:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Extras:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Legt das Verzeichnis für zusätzliche Spieldateien fest."
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Extras:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Spielstände:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Legt fest, wo die Spielstände gespeichert werden."
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Spielstände:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Keiner"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Standard"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "SoundFont auswählen"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Verzeichnis mit Spieldateien auswählen"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Verzeichnis mit zusätzlichen Dateien auswählen"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Verzeichnis für Spielstände auswählen"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Diese Spielkennung ist schon vergeben. Bitte eine andere wählen."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~B~eenden"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "ScummVM beenden"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "Übe~r~"
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Über ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~ptionen"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Globale ScummVM-Einstellungen ändern"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tarten"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Ausgewähltes Spiel starten"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~L~aden..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Spielstand für ausgewähltes Spiel laden"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "Spiel ~h~inzufügen"
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr ""
"Umschalttaste (Shift) gedrückt halten, um Verzeichnisse nach Spielen zu "
"durchsuchen"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "Spielo~p~tionen"
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Spieloptionen ändern"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "Spiel ~e~ntfernen"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Spiel aus der Liste entfernen. Die Spieldateien bleiben erhalten."
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~H~inzufügen"
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "Spielo~p~tion"
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~E~ntfernen"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "In Spieleliste suchen"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Suchen:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Spiel laden:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Laden"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -617,40 +618,40 @@ msgstr ""
"Möchten Sie wirklich den PC nach Spielen durchsuchen? Möglicherweise wird "
"dabei eine größere Menge an Spielen hinzugefügt."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM konnte das gewählte Verzeichnis nicht öffnen!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM konnte im gewählten Verzeichnis kein Spiel finden!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Spiel auswählen:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Möchten Sie wirklich diese Spielkonfiguration entfernen?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Möchten Sie einen Spielstand laden?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr ""
"Für dieses Spiel wird das Laden aus der Spieleliste heraus nicht unterstützt."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM konnte keine Engine finden, um das Spiel zu starten!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Durchsuchen"
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Aufzeichnen"
@@ -693,135 +694,135 @@ msgstr "Wechsle"
msgid "Fast replay"
msgstr "Schneller Modus"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
-msgstr "Niemals"
+msgstr "nie"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "alle 5 Minuten"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "alle 10 Minuten"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "alle 15 Minuten"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "alle 30 Minuten"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Kein SoundFont"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Folgende Grafikoptionen konnten nicht geändert werden:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "Grafikmodus konnte nicht geändert werden."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "Vollbildeinstellung konnte nicht geändert werden."
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr ""
"Einstellung für Seitenverhältniskorrektur konnte nicht geändert werden."
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafikmodus:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Render-Modus:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr ""
"Spezielle Farbmischungsmethoden werden von manchen Spielen unterstützt."
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Vollbildmodus"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Seitenverhältnis korrigieren"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Seitenverhältnis für Spiele mit der Auflösung 320x200 korrigieren"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Bevorzugtes Gerät:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musikgerät:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
"Legt das bevorzugte Tonwiedergabe-Gerät oder den Soundkarten-Emulator fest."
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Legt das Musikwiedergabe-Gerät oder den Soundkarten-Emulator fest."
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Standard-Gerät:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musikgerät:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib-Emulator"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib wird für die Musik in vielen Spielen verwendet."
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Ausgabefrequenz:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -829,68 +830,64 @@ msgstr ""
"Höhere Werte bewirken eine bessere Soundqualität, werden aber möglicherweise "
"nicht von jeder Soundkarte unterstützt."
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM-Gerät:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr ""
"Legt das standardmäßige Musikwiedergabe-Gerät für General-MIDI-Ausgabe fest."
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Keine General-MIDI-Musik"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Erstes verfügbares Gerät"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont wird von einigen Soundkarten, FluidSynth und Timidity unterstützt."
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Gemischter AdLib/MIDI-Modus"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Kombiniert MIDI-Musik mit AdLib-Soundeffekten"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI-Lautstärke:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth-Einstellungen"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32-Gerät:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Legt das standardmäßige Tonwiedergabe-Gerät für die Ausgabe von Roland MT-32/"
"LAPC1/CM32l/CM64 fest."
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Echte Roland MT-32 (GM-Emulation deaktiviert)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -898,16 +895,16 @@ msgstr ""
"Wählen Sie dies aus, wenn Sie ein echtes Roland-kompatibles Soundgerät "
"verwenden"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Echte Roland MT-32 (keine GM-Emulation)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland-GS-Gerät (MT-32-Zuweisungen aktivieren)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -915,174 +912,190 @@ msgstr ""
"Wählen Sie dies aus, wenn Sie ausbessernde Instrumentzuweisungen aktivieren "
"möchten, um MT-32 auf einem Roland-GS-Gerät zu emulieren."
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Keine Roland-MT-32-Musik"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Sprache und Text:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Sprache"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Untertitel"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Beides"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Untertitel-Tempo:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Text u. Sprache:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Spr."
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Text"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "S+T"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Untertitel anzeigen und Sprachausgabe aktivieren"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Text-Tempo:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musiklautstärke:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musiklautstärke:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
-msgstr "Alles aus"
+msgstr "Stumm"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Effektlautstärke:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Lautstärke spezieller Geräusch-Effekte"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Effektlautst.:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Sprachlautstärke:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Sprachlautst.:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth-Einstellungen"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Themen:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Themen:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Legt das Verzeichnis für zusätzliche Spieldateien für alle Spiele in ScummVM "
"fest."
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Plugins:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Plugins:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Andere"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Thema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI-Renderer:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autom. Speichern:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autospeichern:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Tasten"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Sprache:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Sprache der ScummVM-Oberfläche"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "Updates suchen:"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "Wie oft nach Aktualisierungen von ScummVM suchen?"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "Jetzt prüfen"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Sie müssen ScummVM neu starten, damit die Änderungen wirksam werden."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
"In das gewählte Verzeichnis kann nicht geschrieben werden. Bitte ein anderes "
"auswählen."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Verzeichnis für Oberflächen-Themen"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Verzeichnis für zusätzliche Dateien auswählen"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Verzeichnis für Erweiterungen auswählen"
# Nicht übersetzen, da diese Nachricht nur für nicht-lateinische Sprachen relevant ist.
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1100,65 +1113,65 @@ msgstr "# nächste"
msgid "add"
msgstr "hinzufügen"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Löschen"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Vorschau"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Zahlen"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* ABC"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Spiel aufzeichnen/wiedergeben"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Löschen"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Aufnahme"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Wiedergabe"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Bearbeiten"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Autor:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notizen:"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Möchten Sie diese Aufnahme wirklich löschen?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Unbekannter Autor"
@@ -1222,7 +1235,7 @@ msgstr "Erstellt einen neuen Spielstand."
msgid "Name: "
msgstr "Name: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Geben Sie eine Beschreibung für Speicherplatz %d ein:"
@@ -1231,64 +1244,90 @@ msgstr "Geben Sie eine Beschreibung für Speicherplatz %d ein:"
msgid "Select a Theme"
msgstr "Thema auswählen"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX ausgeschaltet"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX ausgeschaltet"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standard-Renderer"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Kantenglättung"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Kantenglättung"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM unterstützt die automatische Suche nach Aktualisierungen,\n"
+"wozu ein Internetzugang erforderlich ist.\n"
+"\n"
+"Möchten Sie diese Funktion aktivieren?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+"(Sie können diese auch jederzeit im Options-Dialog unter dem Reiter "
+"\"Sonstiges\" aktivieren)"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Automatisch nach Aktualisierungen suchen"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Fortfahren"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Wert löschen"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Engine unterstützt den Debug-Level \"%s\" nicht."
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menü"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Überspringen"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pause"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Zeile überspringen"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fehler beim Ausführen des Spiels:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Konnte keine Spiel-Engine finden, die dieses Spiel starten kann."
@@ -1383,18 +1422,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Bernst."
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "täglich"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "wöchentlich"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "monatlich"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<Fehlerhafter Wert>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Das Spiel im Verzeichnis \"%s\" scheint nicht bekannt zu sein."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Bitte geben Sie die folgenden Daten auf Englisch an das ScummVM-Team weiter "
"sowie"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr ""
"den Namen des Spiels, das Sie hinzufügen wollten, als auch die Version/"
@@ -1404,11 +1459,11 @@ msgstr ""
msgid "~R~esume"
msgstr "~F~ortsetzen"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~L~aden"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~S~peichern"
@@ -1433,15 +1488,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Zur Spiele~l~iste"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Speichern:"
@@ -1450,15 +1505,16 @@ msgstr "Speichern:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Speichern"
@@ -1480,13 +1536,13 @@ msgstr ""
"Speichern des Spielstands %s fehlgeschlagen! Bitte lesen Sie die Liesmich-"
"Datei für grundlegende Informationen und Anweisungen zu weiterer Hilfe."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~bbrechen"
@@ -1494,23 +1550,23 @@ msgstr "~A~bbrechen"
msgid "~K~eys"
msgstr "~T~asten"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Konnte Farbenformat nicht initialisieren."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Konnte nicht zu Grafikmodus wechseln: \""
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Konnte Einstellung für Seitenverhältniskorrektur nicht anwenden."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Konnte Einstellung für Vollbildmodus nicht anwenden."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1526,7 +1582,7 @@ msgstr ""
"Lesen Sie die Liesmich-Datei für\n"
"weitere Informationen."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1541,7 +1597,7 @@ msgstr ""
"Spiel hören zu können. Lesen Sie die\n"
"Liesmich-Datei für weitere Informationen."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1550,7 +1606,7 @@ msgstr ""
"Laden des Spielstands %s fehlgeschlagen! Bitte lesen Sie die Liesmich-Datei "
"für grundlegende Informationen und Anweisungen zu weiterer Hilfe."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1561,11 +1617,11 @@ msgstr ""
"und jegliche Spielstände, die Sie erstellen, könnten in zukünftigen "
"Versionen von ScummVM nicht mehr funktionieren."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Trotzdem starten"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib-Emulator"
@@ -1646,11 +1702,11 @@ msgstr "FM-Towns-Audio"
msgid "PC-98 Audio"
msgstr "PC-98-Audio"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "MT-32-Emulator wird gestartet"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32-Emulation"
@@ -1682,7 +1738,7 @@ msgstr "Möchten Sie wirklich beenden?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Beenden"
@@ -1767,11 +1823,11 @@ msgstr "Automatisches Ziehen ist jetzt "
msgid "Swipe three fingers to the right to toggle."
msgstr "Zum Umschalten mit drei Fingern nach rechts wischen."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (ohne Filter)"
@@ -1786,19 +1842,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal ohn.Skalieren"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Seitenverhältniskorrektur an"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Seitenverhältniskorrektur aus"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktiver Grafikfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Fenstermodus"
@@ -1831,7 +1887,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~S~chließen"
@@ -2325,20 +2381,36 @@ msgstr ""
"Vergessen Sie nicht, der Aktion \"Werkzeugleiste verbergen\" eine Taste "
"zuzuweisen, um das ganze Inventar sehen zu können."
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Suche nach Aktualisierungen..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Farbmodus einschalten"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Farbgrafik verwenden"
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "Abtastzeilen/Scanlines"
+
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Abtastzeilen (Scanlines) anzeigen"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Originale Spielstand-Menüs"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2367,27 +2439,49 @@ msgstr ""
"Aktiviere Maus-Unterstützung. Erlaubt die Verwendung der Maus zur Bewegung "
"und in Menüs innerhalb des Spiels."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "Verwende hochauflösende Hercules-Schrift"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+"Verwende hochauflösende Hercules-Schriftart, wenn die Schriftarten-Datei "
+"verfügbar ist."
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "Pausiere, wenn Befehle eingegeben werden"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"Zeige eine Fenster mit einer Kommandozeile und pausiere das Spiel (wie in "
+"SCI) anstelle einer Eingabe in Echtzeit."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Spiel laden:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Laden"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2398,7 +2492,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2409,7 +2503,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2420,7 +2514,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Zwischensequenz \"%s\" nicht gefunden!"
@@ -2451,20 +2545,20 @@ msgstr ""
"Klicken Sie auf OK, um diese jetzt umzuwandeln, sonst werden Sie erneut "
"gefragt, wenn Sie nächstes Mal dieses Spiel starten.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Modus für helle Palette verwenden"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Zeigt Grafiken über helle Spielpalette an."
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Konnte Spielstand aus Datei nicht laden."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Konnte Spielstand nicht in Datei speichern."
@@ -2481,7 +2575,7 @@ msgstr "Schnelles Film-Tempo"
msgid "Play movies at an increased speed"
msgstr "Spielt Filme mit erhöhter Geschwindigkeit ab."
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Konnte Spielstand nicht speichern."
@@ -2660,52 +2754,62 @@ msgstr ""
"\"import_savefile\" verwenden.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "Video vom Anflug auf Myst abspielen"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+"Das Video, welches den Anflug auf Myst zeigt, wurde in der ursprünglichen "
+"Engine nicht abgespielt."
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
-msgstr "Schneller ~R~aumwechsel aktiviert"
+msgstr "~Zip-Modus aktiviert"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "Über~g~änge aktiviert"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
-msgstr "Seite ~w~egwerfen"
+msgstr "Seite ~a~blegen"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
msgstr "~K~arte anzeigen"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
msgstr "Haupt~m~enü"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~W~assereffekt aktiviert"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Szenenbuch-Sequenz in der Chronikhalle überspringen"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Ermöglicht dem Spieler, die Szenenbuch-Sequenz in der Chronikhalle zu "
"überspringen."
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Making-Of-Videos auf Vollbild skalieren"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
"Skaliert die Making-Of-Videos, sodass sie den gesamten Bildschirm ausfüllen."
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2714,23 +2818,23 @@ msgstr ""
"Kann Spiel nicht speichern auf Speicherplatz %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Datei laden"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Spiel wird geladen..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Datei speichern"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Spiel wird gespeichert..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2747,11 +2851,11 @@ msgstr ""
"Klicken Sie auf OK, um diese jetzt umzuwandeln, sonst werden Sie erneut "
"gefragt, wenn Sie nächstes Mal dieses Spiel starten.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM hat alle Speicherstände erfolgreich umgewandelt."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2807,37 +2911,45 @@ msgstr "Alternativer Vorspann"
msgid "Use an alternative game intro (CD version only)"
msgstr "Verwendet einen alternativen Vorspann (nur bei CD-Version)."
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Überspringe EGA-Fehlerdiffusion (Vollfarbige Hintergründe)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Überspringe Fehlerdiffusion in EGA-Spielen, Grafik wird mit allen Farben "
"gezeigt"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
-msgstr "Aktiviere hochauflösende Grafik."
+msgstr "Aktiviere hochauflösende Grafik"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Aktiviere hochauflösende Grafik/Inhalte"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr "Aktiviere schwarze Linien in Videos"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr "Zeichne schwarze Linien über Videos, um die scheinbare Schärfe zu erhöhen"
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Digitale Geräusch-Effekte bevorzugen"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
-msgstr "Bevorzugt digitale Geräusch-Effekte statt synthethisierter."
+msgstr "Bevorzugt digitale Geräusch-Effekte statt synthethisierter"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "IMF/Yamaha FB-01 für MIDI-Ausgabe verwenden"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2845,149 +2957,157 @@ msgstr ""
"Verwendet eine Music-Feature-Karte von IBM oder ein Yamaha-FB-01-FM-"
"Synthetisierungsmodul für die MIDI-Ausgabe."
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "CD-Ton verwenden"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Verwendet CD-Ton anstatt des Tons im Spiel, sofern verfügbar."
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Windows-Mauszeiger verwenden"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Verwendet die Windows-Mauszeiger (kleiner und schwarz-weiß) anstatt der von "
"DOS."
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Silberne Mauszeiger verwenden"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Verwendet alternativen Satz silberner Mauszeiger anstatt der normalen "
"goldenen."
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "Objektzeile zeigen"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "Objektnamen und Verben am unteren Bildrand anzeigen"
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Bitte Disk %c einlegen und Taste drücken"
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Kann %s (%c%d) nicht finden, bitte Taste drücken."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Fehler beim Lesen von Disk %c (%c%d), bitte Taste drücken."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Spielpause. Zum Weiterspielen Leertaste drücken."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Möchten Sie wirklich neu starten? (J/N)J"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Möchten Sie wirklich beenden? (J/N)J"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Spielen"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Legen Sie eine Spielstand-Disk ein."
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Sie müssen eine Bezeichnung eingeben."
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Spiel wurde NICHT gespeichert. (Datenträger voll?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Spiel wurde NICHT geladen."
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Speichere \"%s\""
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Lade \"%s\""
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Name für Spielstand eingeben"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Spielstand zum LADEN auswählen"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Spieltitel)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~Z~urück"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~W~eiter"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Nur Sprache"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Sprachausgabe und Untertitel"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Nur Untertitel"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Sprache & Text"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Wähle einen Schwierigkeitsgrad."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Für Hilfe schauen Sie ins Loom-Handbuch."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Anfänger"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Experte"
@@ -3099,7 +3219,7 @@ msgstr "Zwischen Grafikfiltern wechseln"
#: engines/scumm/help.cpp:102
msgid "Increase / Decrease scale factor"
-msgstr "Größenverhätlnis höher/niedriger"
+msgstr "Größenverhältnis höher/niedriger"
#: engines/scumm/help.cpp:103
msgid "Toggle aspect-ratio correction"
@@ -3524,23 +3644,23 @@ msgstr "Nach rechts fliegen"
msgid "Fly to lower right"
msgstr "Nach unten rechts fliegen"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Blättern einschalten"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Blättern ausschalten"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Musiklautstärke:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Untertitel-Tempo:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3550,7 +3670,7 @@ msgstr ""
"Roland-Upgrade von LucasArts, aber %s\n"
"fehlt. Stattdessen wird AdLib verwendet."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3585,7 +3705,9 @@ msgstr "Originale Spielstand-Menüs verwenden"
msgid ""
"Files button in-game shows original savegame dialog rather than the ScummVM "
"menu"
-msgstr "Dateien-Schaltfläche im Spiel zeigt originales Spielstand-Menü statt dem von ScummVM."
+msgstr ""
+"Dateien-Schaltfläche im Spiel zeigt originales Spielstand-Menü statt dem von "
+"ScummVM."
#: engines/sherlock/detection.cpp:81
msgid "Pixellated scene transitions"
@@ -3603,7 +3725,9 @@ msgstr "Bei Mausbewegung keine Klickpunkte anzeigen"
msgid ""
"Only show hotspot names after you actually click on a hotspot or action "
"button"
-msgstr "Zeigt Klickpunktnamen nur nach Klick auf selbigen oder auf einen Aktionspunkt."
+msgstr ""
+"Zeigt Klickpunktnamen nur nach Klick auf selbigen oder auf einen "
+"Aktionspunkt."
#: engines/sherlock/detection.cpp:101
msgid "Show character portraits"
@@ -3619,7 +3743,8 @@ msgstr "Menüs in Blickfeld gleiten lassen"
#: engines/sherlock/detection.cpp:112
msgid "Slide UI dialogs into view, rather than simply showing them immediately"
-msgstr "Lässt Menüs in Blickfeld gleiten anstatt sie einfach sofort anzuzeigen."
+msgstr ""
+"Lässt Menüs in Blickfeld gleiten anstatt sie einfach sofort anzuzeigen."
#: engines/sherlock/detection.cpp:121
msgid "Transparent windows"
@@ -3733,14 +3858,25 @@ msgstr "Objektnamen zeigen"
msgid "Show labels for objects on mouse hover"
msgstr "Zeigt Objektbeschriftungen bei Mausberührung an."
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "Verwende englische Sprachausgabe"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+"Verwende englische Sprachausgabe anstelle der deutschen, wenn eine andere "
+"Sprache als Deutsch verwendet wird."
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"Ihnen fehlt die Datei \"teenagent.dat\". Laden Sie sich diese von der "
"ScummVM-Website unter http://www.scummvm.org herunter."
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3844,9 +3980,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktiver Filtermodus: nächste Nachbarn"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Roland-GS-Modus"
-
#~ msgid ""
#~ "Your game version has been detected using filename matching as a variant "
#~ "of %s."
diff --git a/po/es_ES.po b/po/es_ES.po
index 1593d4f815..33e4783d32 100644
--- a/po/es_ES.po
+++ b/po/es_ES.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.4.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-24 18:01+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -53,15 +53,16 @@ msgstr "Arriba"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Cancelar"
@@ -100,7 +101,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "¿Seguro que quieres sobrescribir esta partida?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -110,7 +111,7 @@ msgid "Yes"
msgstr "Sí"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -171,7 +172,7 @@ msgstr "Seno"
msgid "Triangle"
msgstr "Triángulo"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Otras"
@@ -203,14 +204,14 @@ msgstr "Reiniciar"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Volver a los valores por defecto de las opciones de FluidSynth"
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -240,15 +241,15 @@ msgstr "Cerrar"
msgid "Mouse click"
msgstr "Clic de ratón"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostrar el teclado"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Asignar teclas"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Activar/Desactivar pantalla completa"
@@ -324,8 +325,8 @@ msgstr ""
"Idioma del juego. No sirve para pasar al inglés la versión española de un "
"juego"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<por defecto>"
@@ -347,11 +348,11 @@ msgstr "Plat.:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Gráficos"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "Gráf."
@@ -364,7 +365,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Opciones gráficas específicas"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Sonido"
@@ -377,11 +378,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Opciones de sonido específicas"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volumen"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volumen"
@@ -395,216 +396,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Opciones de volumen específicas"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Ignorar opciones de MIDI generales"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Opciones de MIDI específicas"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Ignorar opciones de MT-32 generales"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Opciones de MT-32 específicas"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Rutas"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Rutas"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Juego:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Juego:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Adicional:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Especifica un directorio para datos adicionales del juego"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Adicional:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Partidas:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Especifica dónde guardar tus partidas"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Partidas:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ninguna"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Por defecto"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Selecciona un SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Selecciona el directorio del juego"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Selecciona el directorio adicional"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Selecciona el directorio para partidas guardadas"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Esta ID ya está siendo usada. Por favor, elige otra."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~S~alir"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Salir de ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "Acerca ~d~e"
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Acerca de ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pciones..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Cambiar opciones generales de ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~J~ugar"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Jugar al juego seleccionado"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~C~argar..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Cargar partida del juego seleccionado"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~A~ñadir juego..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Mantén pulsado Mayús para añadir varios juegos"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~ditar juego..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Cambiar opciones de juego"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "E~l~iminar juego"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Eliminar el juego de la lista. Los archivos no se borran"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~A~ñadir..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~ditar..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "E~l~iminar"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Buscar en la lista de juegos"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Buscar:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Cargar juego:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Cargar"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -612,40 +614,40 @@ msgstr ""
"¿Seguro que quieres ejecutar la detección masiva? Puede que se añada un gran "
"número de juegos."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "¡ScummVM no ha podido abrir el directorio!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "¡ScummVM no ha encontrado ningún juego en el directorio!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Elige el juego:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "¿Seguro que quieres eliminar la configuración de este juego?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "¿Quieres cargar la partida guardada?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Este juego no permite cargar partidas desde el lanzador."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"¡ScummVM no ha podido encontrar ningún motor capaz de ejecutar el juego!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Añadir varios..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Grabar..."
@@ -688,135 +690,135 @@ msgstr "Volver al juego"
msgid "Fast replay"
msgstr "Repetición rápida"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Nunca"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "cada 5 minutos"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "cada 10 minutos"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "cada 15 minutos"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "cada 30 minutos"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ninguno"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Fallo al aplicar algunos cambios en las opciones gráficas:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "no se ha podido cambiar el modo de vídeo."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "no se ha podido cambiar el ajuste de pantalla completa"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "no se ha podido cambiar el ajuste de corrección de aspecto"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Modo gráfico:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Renderizado:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Modos especiales de difuminado compatibles con algunos juegos"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Pantalla completa"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Corrección de aspecto"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Corregir relación de aspecto en juegos 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Disp. preferido:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Disp. de música:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
"Especifica qué dispositivo de sonido o emulador de tarjeta de sonido "
"prefieres"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr ""
"Especifica el dispositivo de sonido o emulador de tarjeta de sonido de salida"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Disp. preferido:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Disp. de música:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Emul. de AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib se usa para la música en muchos juegos"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Frec. de salida:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -824,68 +826,64 @@ msgstr ""
"Los valores más altos ofrecen mayor calidad, pero puede que tu tarjeta de "
"sonido no sea compatible"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Dispositivo GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Especifica el dispositivo de salida General MIDI por defecto"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "No usar música General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Utilizar el primer dispositivo disponible"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont es compatible con algunas tarjetas de sonido, con FluidSynth y con "
"Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Modo AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Usar tanto MIDI como AdLib en la generación de sonido"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Ganancia MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Opciones de FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Disp. MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Especifica el dispositivo de sonido para la salida Roland MT-32/LAPC1/CM32l/"
"CM64 por defecto"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 auténtica (desactivar emulación GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -893,16 +891,16 @@ msgstr ""
"Marcar si se quiere usar un dispositivo de sonido real conectado al "
"ordenador y compatible con Roland"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 real (sin emulación GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Dispositivo Roland GS (activar conversión MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -910,170 +908,186 @@ msgstr ""
"Marca esta opción si quieres activar la conversión para emular una MT-32 en "
"un dispositivo Roland GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "No usar música Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Texto y voces:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Voces"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Subtítulos"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Ambos"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Vel. de subtítulos:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Texto y voces:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Voz"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Subt"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "V&S"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Reproducir voces y subtítulos"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Vel. de subt.:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Música:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Música:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Silenciar"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Efectos:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volumen de los efectos de sonido"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Efectos:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Voces:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Voces:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Opciones de FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Temas:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Temas:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Especifica el directorio adicional usado por los juegos y ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Plugins:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Plugins:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Otras"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Interfaz:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autoguardado:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autoguardado:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Teclas"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Idioma:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Idioma de la interfaz de ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Tienes que reiniciar ScummVM para aplicar los cambios."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
"No se puede escribir en el directorio elegido. Por favor, selecciona otro."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Selecciona el directorio de temas"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Selecciona el directorio adicional"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Selecciona el directorio de plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1090,65 +1104,65 @@ msgstr "# siguiente"
msgid "add"
msgstr "añadir"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Borrar personaje"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Num"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Grabar o reproducir vídeos"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Borrar"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Grabar"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Reproducción"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Editar"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Autor:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notas:"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "¿Seguro que quieres borrar esta grabación?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Autor desconocido"
@@ -1212,7 +1226,7 @@ msgstr "Guarda una nueva partida"
msgid "Name: "
msgstr "Nombre:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Introduce una descripción para la ranura %d:"
@@ -1221,64 +1235,85 @@ msgstr "Introduce una descripción para la ranura %d:"
msgid "Select a Theme"
msgstr "Selecciona un tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Gráf. desactivados"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Gráf. desactivados"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Estándar"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Estándar"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Suavizado"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Suavizado"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Buscar actualizaciones..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Eliminar valor"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "El motor no es compatible con el nivel de debug '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menú"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Saltar"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pausar"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Saltar frase"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Error al ejecutar el juego:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "No se ha podido encontrar ningún motor capaz de ejecutar el juego"
@@ -1373,16 +1408,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules ámbar"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Eliminar valor"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "El juego en '%s' parece ser desconocido."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Por favor, envía al equipo de ScummVM esta información junto al nombre"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "del juego que has intentado añadir y su versión/idioma/etc.:"
@@ -1390,11 +1442,11 @@ msgstr "del juego que has intentado añadir y su versión/idioma/etc.:"
msgid "~R~esume"
msgstr "~R~eanudar"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~C~argar"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~G~uardar"
@@ -1419,15 +1471,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~olver al lanzador"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Guardar partida"
@@ -1436,15 +1488,16 @@ msgstr "Guardar partida"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Guardar"
@@ -1468,13 +1521,13 @@ msgstr ""
"archivo README para encontrar información básica e instrucciones sobre cómo "
"obtener más ayuda."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~S~í"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~C~ancelar"
@@ -1482,23 +1535,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "No se ha podido iniciar el formato de color."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "No se ha podido cambiar al modo de video: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "No se ha podido aplicar el ajuste de corrección de aspecto"
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "No se ha podido aplicar el ajuste de pantalla completa."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1512,7 +1565,7 @@ msgstr ""
"copiar los archivos del juego al disco duro.\n"
"Consulta el archivo README para más detalles."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1526,7 +1579,7 @@ msgstr ""
"poder escuchar la música del juego.\n"
"Consulta el archivo README para más detalles."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1536,7 +1589,7 @@ msgstr ""
"README para encontrar información básica e instrucciones sobre cómo obtener "
"más ayuda."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1546,11 +1599,11 @@ msgstr ""
"ScummVM. Por lo tanto, puede que sea inestable, y que las partidas que "
"guardes no funcionen en versiones futuras de ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Jugar aun así"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Emulador de AdLib"
@@ -1631,11 +1684,11 @@ msgstr "FM-Towns Audio"
msgid "PC-98 Audio"
msgstr "PC-98 Audio"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Iniciando el emulador de MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Emulador de MT-32"
@@ -1667,7 +1720,7 @@ msgstr "¿Seguro que quieres salir?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Salir"
@@ -1752,11 +1805,11 @@ msgstr "El modo de arrastre automático está"
msgid "Swipe three fingers to the right to toggle."
msgstr "Desliza tres dedos hacia la derecha para cambiar de modo."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (sin filtros)"
@@ -1771,19 +1824,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Activar la corrección de aspecto"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Desactivar la corrección de aspecto"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Filtro de gráficos activo:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Modo ventana"
@@ -1816,7 +1869,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "Cerra~r~"
@@ -2309,20 +2362,38 @@ msgstr ""
"No olvides asignar una tecla a la acción 'Ocultar barra de tareas' para ver "
"todo el inventario"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Buscar actualizaciones..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Modo para daltónicos"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostrar etiquetas de objetos"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Usar pantallas de guardar/cargar originales"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2351,27 +2422,46 @@ msgstr ""
"Activa el ratón. Permite usar el ratón para moverse en el juego y en los "
"menús."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules verde"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Cargar partida:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Cargar"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2382,7 +2472,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2393,7 +2483,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2404,7 +2494,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "No se ha encontrado el vídeo '%s'"
@@ -2435,20 +2525,20 @@ msgstr ""
"Pulsa Aceptar para actualizarlas, si no lo haces este mensaje volverá a "
"aparecer la próxima vez.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Usar paleta original"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Utilizar los niveles de brillo originales del juego"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Fallo al cargar el estado del juego desde el archivo."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Fallo al guardar el estado del juego en el archivo."
@@ -2465,7 +2555,7 @@ msgstr "Velocidad rápida de vídeos"
msgid "Play movies at an increased speed"
msgstr "Reproducir vídeos a mayor velocidad"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Fallo al guardar la partida"
@@ -2639,50 +2729,60 @@ msgstr ""
"'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "Modo ~Z~ip activado"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "Tra~n~siciones activadas"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~T~irar página"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~M~ostrar el mapa"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~M~enú principal"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "Efecto ag~u~a activado"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Saltar las escenas del salón de registros"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Permitir al jugador saltarse las escenas storyboard del salón de registros"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Redimensionar vídeos a pantalla completa"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Redimensionar los vídeos para que utilicen toda la pantalla"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2691,23 +2791,23 @@ msgstr ""
"No se puede guardar en la ranura %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Cargar partida"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Cargando partida..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Guardar partida"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Guardando partida..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2724,11 +2824,11 @@ msgstr ""
"Pulsa Aceptar para actualizarlos, si no lo haces este mensaje volverá a "
"aparecer la próxima vez.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM ha convertido todas las partidas guardadas correctamente."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2785,37 +2885,46 @@ msgid "Use an alternative game intro (CD version only)"
msgstr ""
"Usa una introducción alternativa para el juego (solo para la versión CD)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Omitir difuminado EGA (colores completos)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Omitir pasada de difuminado en los juegos EGA. Los gráficos se muestran con "
"los colores completos"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Activar gráficos de alta resolución"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Activar gráficos/contenido de alta resolución"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Activar modo Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Preferir efectos de sonido digitales"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Preferir efectos de sonido digitales en vez de los sintetizados"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Usar IMF/Yamaha FB-01 para la salida MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2823,147 +2932,156 @@ msgstr ""
"Usar una tarjeta IBM Music o un módulo sintetizador Yamaha FB-01 FM para la "
"salida MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Usar CD audio"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Usar CD audio en vez del sonido interno del juego, si está disponible"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Usar cursores de Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Usar los cursores de Windows (más pequeños y monocromos) en vez de los de DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Usar cursores plateados"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Usar los cursores plateados alternativos, en vez de los dorados normales"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Mostrar etiquetas de objetos"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Inserta el disco %c y pulsa un botón para continuar."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "No se ha podido encontrar %s, (%c%d) Pulsa un botón."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Error leyendo el disco %c, (%c%d) Pulsa un botón."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Juego pausado. Pulsa Espacio para continuar."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "¿Seguro que quieres reiniciar? (S/N)S"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "¿Seguro que quieres salir? (S/N)S"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Jugar"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Inserta el disco de las partidas guardadas"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Tienes que introducir un nombre"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "La partida no se ha guardado (¿disco lleno?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "La partida no se ha cargado"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Guardando '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Cargando '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Pon nombre a tu partida"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Selecciona un juego para cargar"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Título del juego)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~A~nterior"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "Si~g~uiente"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Solo voces"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voces y subtítulos"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Solo subtítulos"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voces y sub."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selecciona un nivel de dificultad."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Consulta el manual para obtener más información."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Práctica"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Experto"
@@ -3500,23 +3618,23 @@ msgstr "Volar a la derecha"
msgid "Fly to lower right"
msgstr "Volar abajo y a la derecha"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Desplazamiento mediante toques"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Desplazamiento normal"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Volumen de la música:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Vel. de subtítulos:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3525,7 +3643,7 @@ msgstr ""
"El soporte MIDI nativo requiere la actualización Roland de LucasArts,\n"
"pero %s no está disponible. Se usará AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3711,14 +3829,23 @@ msgstr "Mostrar etiquetas de objetos"
msgid "Show labels for objects on mouse hover"
msgstr "Muestra las etiquetas de los objetos al pasar el ratón"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"No se encuentra el archivo 'teenagent.dat'. Descárgalo de la página de "
"ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3818,6 +3945,3 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Modo de filtro activo: más cercano"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Activar modo Roland GS"
diff --git a/po/eu.po b/po/eu.po
index a8dfe66cb1..e0100ed169 100644
--- a/po/eu.po
+++ b/po/eu.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.5.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2011-12-15 14:53+0100\n"
"Last-Translator: Mikel Iturbe Urretxa <mikel@hamahiru.org>\n"
"Language-Team: Librezale <librezale@librezale.org>\n"
@@ -52,15 +52,16 @@ msgstr "Joan gora"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Utzi"
@@ -99,7 +100,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Gainidatzi fitxategia?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -109,7 +110,7 @@ msgid "Yes"
msgstr "Bai"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -170,7 +171,7 @@ msgstr "Sinua"
msgid "Triangle"
msgstr "Triangelua"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Beste"
@@ -202,14 +203,14 @@ msgstr "Berrezarri"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Berrazarri FluidSynth-en ezarpen guztiak bere balio lehenetsietara"
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -237,15 +238,15 @@ msgstr "Itxi"
msgid "Mouse click"
msgstr "Sagu-klika"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Erakutsi teklatua"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Esleitu teklak"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Txandakatu pantaila osoa"
@@ -320,8 +321,8 @@ msgid ""
msgstr ""
"Jokoaren hizkuntza. Honek ez du zure ingelesezko bertsioa frantsesera pasako"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<lehenetsia>"
@@ -343,11 +344,11 @@ msgstr "Plataforma:"
msgid "Engine"
msgstr "Motorea"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafikoak"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -360,7 +361,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Ezarpen grafiko globalak baliogabetu"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Soinua"
@@ -373,11 +374,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Soinu ezarpen globalak baliogabetu"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Bolumena"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Bolumena"
@@ -391,216 +392,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Bolumen ezarpen globalak baliogabetu"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "MIDI ezarpen globalak baliogabetu"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "MIDI ezarpen globalak baliogabetu"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "MT-32 ezarpen globalak baliogabetu"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "MT-32 ezarpen globalak baliogabetu"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Bide-izenak"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Bideak"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Jokoa:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Jokoa:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Gehigarriak:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Jokoak erabiltzen duen datu gehigarrien bide-izena"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Gehigarria:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Partida gordeak:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Zure gordetako partidak non gordeko diren zehazten du"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Partida gordeak:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Bat ere ez"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Lehenetsia"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "SoundFont-a aukeratu"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Jokoaren direktorioa aukeratu"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Direktorio gehigarria aukeratu"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Partida gordeen direktorioa aukeratu"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "ID hau jada erabilia izaten ari da. Mesedez, aukeratu beste bat."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~I~rten"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Irten ScummVM-tik"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "Ho~n~i buruz..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "ScummVM-i buruz"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~A~ukerak"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "ScummVM-ren aukera globalak aldatu"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~H~asi"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Aukeraturiko jokora jolastu"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~K~argatu"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Aukeraturiko jokorako partida gordea kargatu"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~G~ehitu..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Shift mantendu sakaturik hainbat joko gehitzeko"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~ditatu..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Aldatu jokoaren aukerak"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~K~endu jokoa"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Jokoa zerrendatik kendu. Jokoaren fitxategiak ez dira ezabatzen"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~G~ehitu..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~ditatu..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~K~endu"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Bilatu joko-zerrendan"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Bilatu:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Jokoa kargatu:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Kargatu"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -608,41 +610,41 @@ msgstr ""
"Joko detektatzaile masiboa exekutatu nahi al duzu? Honek joko kantitate "
"handia gehitu dezake."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM-k ezin izan du zehazturiko direktorioa ireki!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM-k ezin izan du jokorik aurkitu zehazturiko direktorioan!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Jokoa aukeratu:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Benetan ezabatu nahi duzu joko-konfigurazio hau?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Gordetako jokoa kargatu?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Joko honek ez du uzten partidak abiarazletik kargatzen."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM-k ezin izan du aukeraturiko jokoa exekutatzeko gai den motorerik "
"aurkitu!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Gehitu hainbat..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Grabatu..."
@@ -687,132 +689,132 @@ msgstr "Aldatu jokora"
msgid "Fast replay"
msgstr "Errepikappen bizkorra"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Inoiz ez"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "5 minuturo"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "10 minuturo"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "15 minuturo"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "30 minuturo"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Bat ere ez"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Ezin izan da grafikoen aukeretako batzuk aplikatu:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "ezin izan da bideo-modua aldatu."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "ezin izan da pantaila-osoaren ezarpena aldatu"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "formatu-ratioaren ezarpena ezin izan da aldatu"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Modu grafikoa:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Renderizazioa:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Joko batzuk onarturiko lausotze-modu bereziak"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Pantaila osoa"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Formatu-ratioaren zuzenketa"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "320x200 jokoentzako formatu-ratioa zuzendu"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Gogoko gailua:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musika gailua:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Gogoko soinu txartel edo emuladorea zein den ezartzen du"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Irteerako soinu txartel edo emuladorea ezartzen du"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Gail. gogokoa:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musika gailua:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emuladorea:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib musikarako hainbat jokotan erabiltzen da"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Irteera maizt.:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -820,68 +822,64 @@ msgstr ""
"Balio altuagoek soinu kalitate hobea ezartzen dute, baina baliteke zure "
"soinu-txartela bateragarria ez izatea"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM gailua:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Defektuzko soinu txartela ezartzen du General MIDI irteerarako"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Ez erabili General MIDI musika"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Erabilgarri dagoen lehen gailua erabili"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"Zenbait soinu txartel bateragarriak dira SoundFont-ekin, FluidSynth eta "
"Timidity besteak beste"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "AdLib/MIDI modua"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Soinua sortzerakoan MIDI eta AdLib erabili"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI irabazia:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth Ezarpenak"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 gailua:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Roland MT-32/LAPC1/CM32l/CM64 irteerarako defektuzko soinu txartela ezartzen "
"du"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Benetako Roland MT-32 (GM emulazio gabe)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -889,16 +887,16 @@ msgstr ""
"Markatu ordenagailura konektaturiko Roland-ekin bateragarria den soinu-"
"gailua erabiltzeko"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Benetako Roland MT-32 (GM emulazio gabe)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS Gailua (gaitu MT-32 bihurketak)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -906,170 +904,186 @@ msgstr ""
"Markatu Roland GS gailu batean MT-32 bat emulatzea ahalbidetzen "
"dutenbihurketak gaitzeko"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Ez erabili Roland MT-32 musika"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Testu eta ahotsa:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Ahotsa"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Azpitituluak"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Biak"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Azpitit. abiadura:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Testu eta ahotsa:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Ahots."
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Azp."
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Biak"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Ahotsak erreproduzitu eta azpitituluak erakutsi"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Azpit. abiadura:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musika:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musika:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Mututu dena"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Efektuak:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Soinu efektu berezien bolumena"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Efektuak:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Ahotsak:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Ahotsak:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth Ezarpenak"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Gaiak:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Gaiak:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Joko guztiek edo ScummVM-k darabilten datu gehigarrien bide-izena ezartzen du"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Pluginak:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Pluginak:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Beste"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Gaia:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Interfazea:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autogordetzea:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autogordetzea:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Teklak"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Hizkuntza"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "ScummVM interfazearen hizkuntza"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "ScummVM berrabiarazi behar duzu aldaketak indarrean jartzeko"
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Aukeraturiko direktorioan ezin da idatzi. Mesedez, aukeratu beste bat."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Gaien direktorioa aukeratu"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Fitxategi gehigarrien direktorioa aukeratu"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Pluginen direktorioa aukeratu"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1086,65 +1100,65 @@ msgstr "# hurrengoa"
msgid "add"
msgstr "gehitu"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Ezabatu karakterea"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Zenb"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Grabatu edo erreproduzitu jokoko akzioa"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Ezabatu"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Grabatu"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Erreproduzitu"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Editatu"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Egilea: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Oharrak: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Ezabatu grabazio hau?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Egile ezezaguna"
@@ -1208,7 +1222,7 @@ msgstr "Sortu joko gorde berria"
msgid "Name: "
msgstr "Izena: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Sartu deskribapena %d zirrikiturako: "
@@ -1217,64 +1231,85 @@ msgstr "Sartu deskribapena %d zirrikiturako: "
msgid "Select a Theme"
msgstr "Gaia aukeratu"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX desgaituta"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX desgaituta"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Errendatzaile estandarra"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Estandarra"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Errendatzaile lausotua"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Lausotua"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Eguneraketak bilatzen..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Balioa kendu:"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Motoreak ez da '%s' debug mailarekin bateragarria"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menua"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Saltatu"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Gelditu"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Lerroa saltatu"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Jokoa exekutatzean errorea:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Ezin izan da aukeraturiko jokoa exekutatzeko gai den motorerik aurkitu"
@@ -1369,16 +1404,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Herkules anbar-kolorekoa"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Balioa kendu:"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "'%s'-(e)ko jokoa ezezaguna dela dirudi"
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Mesedez, bidali hurrengo datuak ScummVM taldeari gehitzen saiatu zaren"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "jokoaren izen, bertsio/hizkuntza/e.a.-ekin batera:"
@@ -1386,11 +1438,11 @@ msgstr "jokoaren izen, bertsio/hizkuntza/e.a.-ekin batera:"
msgid "~R~esume"
msgstr "~J~arraitu"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "Ka~r~gatu"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~G~orde"
@@ -1415,15 +1467,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "It~z~uli abiarazlera"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Gorde jokoa:"
@@ -1432,15 +1484,16 @@ msgstr "Gorde jokoa:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Gorde"
@@ -1462,13 +1515,13 @@ msgstr ""
"Jokoaren egoera gordetzeak huts egin du (%s)! Jo ezazu README-ra oinarrizko "
"informaziorako eta laguntza gehiago nola jaso jakiteko."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~A~dos"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~U~tzi"
@@ -1476,23 +1529,23 @@ msgstr "~U~tzi"
msgid "~K~eys"
msgstr "~T~eklak"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kolore formatua ezin izan da hasieratu."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Ezin izan da aldatu bideo modura : '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Ezin izan da formatu-ratio ezarpena aplikatu."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Ezin izan da pantaila-osoa ezarpena aplikatu."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1506,7 +1559,7 @@ msgstr ""
"fitxategiak disko gogorrera kopiatzea.\n"
"Jo README fitxategira xehetasunetarako."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1520,7 +1573,7 @@ msgstr ""
"izateko. Jo README fitxategira\n"
"xehetasunetarako."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1529,7 +1582,7 @@ msgstr ""
"Jokoaren egoera kargatzeak huts egin du (%s)! Jo ezazu README-ra oinarrizko "
"informaziorako eta laguntza gehiago nola jaso jakiteko."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1539,11 +1592,11 @@ msgstr ""
"Hori dela eta, ezegonkorra izan daiteke eta gerta daiteke gordeta izan "
"ditzakezun partidan ez ibiltzea ScummVM-ren etorkizuneko bertsioetan."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Jolastu berdin-berdin"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib emuladorea"
@@ -1624,11 +1677,11 @@ msgstr "FM-Towns soinua"
msgid "PC-98 Audio"
msgstr "PC-98 Soinua"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "MT-32 emuladorea hasieratzen"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 emuladorea"
@@ -1660,7 +1713,7 @@ msgstr "Benetan irten?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Irten"
@@ -1745,11 +1798,11 @@ msgstr "Auto-arrastatzea orain:"
msgid "Swipe three fingers to the right to toggle."
msgstr "Pasatu hiru atzamar eskuinean gaitu/desgaitzeko."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (Iragazi gabe)"
@@ -1764,19 +1817,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normala"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Formatu-ratio zuzenketa gaituta"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Formatu-ratio zuzenketa desgaituta"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Filtro grafiko aktiboa:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Leiho modua"
@@ -1809,7 +1862,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~I~txi"
@@ -2302,20 +2355,38 @@ msgstr ""
"Ez ahaztu 'tresna-barra ezkutatu' ekintza tekla bati esleitzea inbentario "
"osoa ikusteko"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Eguneraketak bilatzen..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Daltonikoentzako modua"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Erakutsi objektuen etiketak"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Erabili jatorrizko gorde/kargatu pantailak"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2344,27 +2415,46 @@ msgstr ""
"Saguaren euskarria giatzen du. Sagua mugitzeko eta jokoko menuetan "
"erabiltzea ahalbidetzen du"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Herkules berdea"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Jokoa kargatu:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Kargatu"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2375,7 +2465,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2386,7 +2476,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2397,7 +2487,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "'%s' bideo fitxategia ez da aurkitu!"
@@ -2428,20 +2518,20 @@ msgstr ""
"Sakatu Ados orain konbertitzeko, bestela berriz galdetuko dizut jokoa berriz "
"martxan jartzen duzunean.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Erabili paleta argia"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Erakutsi grafikoak jokoaren paleta argia erabilita"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Ezin izan da fitxategitik jokoa kargatu."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Ezin izan da jokoa fitxategira gorde."
@@ -2458,7 +2548,7 @@ msgstr "Bideo abiadura azkarra"
msgid "Play movies at an increased speed"
msgstr "Erreproduzitu bidoeak abiadura handiagoan"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Ezin izan da jokoa gorde"
@@ -2632,50 +2722,60 @@ msgstr ""
"nahi izanez gero ScummVM debug konsola ireki eta 'import_savefile'\n"
"agindau erabili.\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ip modua aktibaturik"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~T~rantsizioak gaituta"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "Orria ~b~ota"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~M~apa erakutsi"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "Menu ~n~agusia"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~U~r-efektua gaituta"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Saltatu Hall of Records-eko eszenak"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Erabiltzaileari Halls of Records-eko eszenak ez ikusteko aukera ematen dio"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Eskalatu bideoen egitea pantaila osora"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Eskalatu bideoak egiteko era, pantaila osoa erabili dezaten"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2684,23 +2784,23 @@ msgstr ""
"Ezin da partida gorde %i zirrikituan\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Kargatu fitxategia:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Jokoa kargatzen..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Gorde fitxategia"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Jokoa gordetzen..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2717,11 +2817,11 @@ msgstr ""
"Sakatu Ados orain konbertitzeko, bestela berriz galdetuko dizut jokoa berriz "
"martxan jartzen duzunean.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM-k ondo konbertitu ditu zure gordetako partida guztiak."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2777,36 +2877,45 @@ msgstr "Sarrera alternatiboa"
msgid "Use an alternative game intro (CD version only)"
msgstr "Erabili sarrera alternatiboa (CD bertsioa soilik)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Saihestu EGA leuntze pausua (koloretako hondoak)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Saihestu leuntzea EGA jokoetan, grafikoak kolore guztiekin erakustendira"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Gaitu erresoluzio altuko grafikoak"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Gaitu erresoluzio altuko grafikoak/edukiak"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Roland GS modua gaitu"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Lehenetsi soinu efektu digitalak"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Lehenetsi soinu efektu digitalak sintetizatuen ordez"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Erabili IMF/Yamaha FB-01 MIDI irteerarako"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2814,149 +2923,158 @@ msgstr ""
"Erabili IBM Music Feature txartela edo Yamaha FB-01 FM "
"sintetizatzailemodulua MIDI irteerarako"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Erabili audio CDa"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Erabili CD-ko audioa jokokoa beharrean, eskurarri badago"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Erabili Windows-eko kurtsoreak"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Erabili Windows-eko kurtsoreak (txikiagoak eta monokromoak) DOS-ekoak "
"erabilibeharrean"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Erabili zilarrezko kurtsoreak"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Erabili zilar kolorezko kurtsore multzo alternatiboa, urre-koloreko "
"kursorenormalak erabili beharrean"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Erakutsi objektuen etiketak"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "%c diskoa sartu eta sakatu botoi bat jarraitzeko."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Ezin izan da %s, (%c%d) aurkitu. Sakatu botoi bat"
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "%c, (%c%d) diskoa irakurtzean errorea. Sakatu botoia."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Joko pausatua. Sakatu ZURIUNEA jarraitzeko."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Berrabiarazi? (B/E)B"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Irten? (B/E)B"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Jolastu"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Sartu partida gordeak dituen diskoa"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Izen bat sartu behar duzu"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Jokoa EZ da gorde (diskoa beteta?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Jokoa EZ da kargatu"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "'%s' gordetzen"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "'%s' kargatzen"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Izendatu zure partida"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Aukeratu kargatzeko partida"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Jokoaren izena)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~A~urrekoa"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~H~urrengoa"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Ahotsak bakarrik"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Ahotsak eta azpitituluak"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Azpitituluak bakarrik"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Ahotsak & azpit."
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Zailtasuna aukeratu."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Loom(TM)-ko eskuliburura jo ezazu laguntza lortzeko."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Entrenamendua"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Aditua"
@@ -3493,23 +3611,23 @@ msgstr "Eskuinera hegan egin"
msgid "Fly to lower right"
msgstr "Behera eta eskuinera hegan egin"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Heldutako korritze barra gaituta"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Heldutako korritze barra desgaituta"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Musika: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Azpitit. abiadura:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3518,7 +3636,7 @@ msgstr ""
"MIDI euskarri natiboak LucasArts-en Roland eguneraketa behar du,\n"
"baina %s ez dago eskuragarri. AdLib erabiliko da."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3553,8 +3671,8 @@ msgid ""
"Files button in-game shows original savegame dialog rather than the ScummVM "
"menu"
msgstr ""
-"Jokoko Fitxategiak botoiak jatorrizko jokoa gordetzeko elkarrizketak erakusten "
-"ditu, ScummVM-ren elkarrizketak erakutsi beharrean"
+"Jokoko Fitxategiak botoiak jatorrizko jokoa gordetzeko elkarrizketak "
+"erakusten ditu, ScummVM-ren elkarrizketak erakutsi beharrean"
#: engines/sherlock/detection.cpp:81
msgid "Pixellated scene transitions"
@@ -3590,8 +3708,8 @@ msgstr "Irristatu elkarrizketak"
#: engines/sherlock/detection.cpp:112
msgid "Slide UI dialogs into view, rather than simply showing them immediately"
-msgstr "Irristatu UI elkarrizketak pantailara, osorik bat-batean erakutsi "
-"beharrean"
+msgstr ""
+"Irristatu UI elkarrizketak pantailara, osorik bat-batean erakutsi beharrean"
#: engines/sherlock/detection.cpp:121
msgid "Transparent windows"
@@ -3700,12 +3818,21 @@ msgstr "Erakutsi objektuen etiketak"
msgid "Show labels for objects on mouse hover"
msgstr "Erakutsi objektuen etiketak sagua pasatzean"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "'teenagent.dat' fitxategia falta da. Eskuratu ScummVM webgunean"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3806,6 +3933,3 @@ msgstr "Erabili DVD bertsioko MPEG bideoa, bereizmen baxuagoko AVI-a beharrean"
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Filtro aktibo modua: hurbilena"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Roland GS modua gaitu"
diff --git a/po/fi_FI.po b/po/fi_FI.po
index a306d8e537..e073d23af6 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.6.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2012-12-01 19:37+0200\n"
"Last-Translator: Toni Saarela <saarela@gmail.com>\n"
"Language-Team: Finnish\n"
@@ -54,15 +54,16 @@ msgstr "Siirry ylös"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Peruuta"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Haluatko varmasti poistaa tämän pelitallennuksen?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "Kyllä"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -176,7 +177,7 @@ msgstr ""
msgid "Triangle"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Muut"
@@ -208,14 +209,14 @@ msgstr ""
msgid "Reset all FluidSynth settings to their default values."
msgstr ""
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -244,15 +245,15 @@ msgstr "Sulje"
msgid "Mouse click"
msgstr "Hiiren klikkaus"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Näytä näppäimistö"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Määritä näppäimet uudelleen"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Kokoruututilan vaihto"
@@ -328,8 +329,8 @@ msgstr ""
"Pelin kieli. Tämä ei muuta esimerkiksi espanjankielistä versiota pelistä "
"englanninkieliseksi."
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<oletus>"
@@ -351,11 +352,11 @@ msgstr "Alusta:"
msgid "Engine"
msgstr "Moottori"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafiikka"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -368,7 +369,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Ohita globaalit grafiikka-asetukset"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Ääni"
@@ -381,11 +382,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Ohita globaalit ääniasetukset"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Voimakkuus"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Voimakkuus"
@@ -399,216 +400,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Ohita globaalit äänenvoimakkuusasetukset"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Ohita globaalit MIDI-asetukset"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Ohita globaalit MIDI-asetukset"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Ohita globaalit MT-32 asetukset"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Ohita globaalit MT-32 asetukset"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Polut"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Polut"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Pelin polku:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Pelin polku:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Lisäkansio:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Määrittää polun lisätiedostoihin joita peli mahdollisesti käyttää"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Lisäkansio:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Tallennuskansio:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Määrittää polun pelitallennuksille"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Tallennuskansio:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ei määritelty"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Oletus"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Valitse äänifontti"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Valitse pelin kansio"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Valitse lisäkansio pelille"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Valitse kansio pelitallennuksille"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Pelin tunnus on jo käytössä. Valitse jokin muu."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~L~opeta"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Lopeta ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "Tietoa..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Tietoa ScummVM:stä"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~A~setukset"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Muuta globaaleja ScummVM:n asetuksia"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~P~elaa"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Pelaa valittua peliä"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~L~ataa..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Lataa pelitallennus valitulle pelille"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~L~isää peli..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Pidä Shift-näppäintä pohjassa lisätäksesi useita pelejä kerralla"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "Muokkaa peliä..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Muuta pelin asetuksia"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "Poista peli"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Poista peli listasta. Pelin tiedostoja ei poisteta levyltä"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "Lisää peli..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "Muokkaa peliä..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "Poista peli..."
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Etsi peliä listasta"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Etsi:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Lataa peli:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Lataa"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -616,40 +618,40 @@ msgstr ""
"Haluatko varmasti lisätä pelejä alihakemistoineen? Tämä voi lisätä suuren "
"määrän pelejä."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ei voi avata kyseistä hakemistoa!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ei löytänyt yhtään peliä kyseisestä hakemistosta!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Valitse peli:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Haluatko varmasti poistaa pelin asetuksineen listalta?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
#, fuzzy
msgid "Do you want to load saved game?"
msgstr "Haluatko tallentaa vai ladata pelin?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Tämä peli ei tue pelitallennuksien lataamista pelin ulkopuolelta."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ei löytänyt pelimoottoria joka tukee valittua peliä!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Lisää monta..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -698,134 +700,134 @@ msgstr "Vaihda"
msgid "Fast replay"
msgstr "Nopea moodi"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Ei koskaan"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "5 minuutin välein"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "10 minuutin välein"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "15 minuutin välein"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "30 minuutin välein"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ei käytössä"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Joitain grafiikka-asetuksia ei saatu asetettua:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "videotilaa ei voitu vaihtaa."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "kokoruututilaa ei voitu muuttaa"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "kuvasuhdekorjausasetusta ei voitu muuttaa"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafiikkatila:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Renderöintitila:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Erityiset dithering asetukset joita jotkut pelit tukevat"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Kokoruututila"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Kuvasuhteen korjaus"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Oikea kuvasuhde 320x200 peleille"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Ensisijainen laite:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musiikkilaite:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
"Määrittää äänilaitteen tai äänikorttiemulaattorin jota ensisijaisesti tulisi "
"käyttää"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Määrittää äänikortin tai äänikorttia emuloivan ohjelmiston"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Ensisijainen:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musiikkilaite:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emulaattori:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLibiä käytetään monien pelien musiikeissa"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Taajuus:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -833,65 +835,61 @@ msgstr ""
"Isommat taajuudet merkitsevät parempaa äänenlaatua, mutta äänikorttisi ei "
"ehkä tue niitä."
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM laite:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Määrittää oletuksena käytettävän äänilaitteen General MIDIlle"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Älä käytä General MIDIä musiikissa"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Käytä ensimmäistä laitetta"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "Äänifontti:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"Jotkut äänikortit tukevat äänifonttia (SoundFont), FluidSynth ja Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "Äänifontti:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Yhdistetty AdLib/MIDI tila"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Käytä sekä MIDIä että Adlibiä äänentuotantoon"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDIn äänilisäys:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr ""
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 laite:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr "Määrittää oletusäänilaitteen Roland MT-32/LAPC1/CM32l/CM64:n käyttöön"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Aito Roland MT-32 (ei GM emulointia)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -899,187 +897,203 @@ msgstr ""
"Valitse jos haluat käyttää aitoa Roland-yhteensopivaa laittetta joka on "
"kytketty tietokoneeseesi"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Aito Roland MT-32 (ei GM emulointia)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
#, fuzzy
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Aito Roland MT-32 (ei GM emulointia)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
msgstr ""
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Älä käytä Roland MT-32 musiikkia"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Tekstitys ja puhe:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Puhe"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Tekstitys"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Molemmat"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Tekstin nopeus:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Tekstitys ja puhe:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Puhe"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Tekstit"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Molemmat"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Näytä tekstitys ja käytä puhetta"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Tekstin nopeus:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musiikki:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musiikki:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Vaimenna"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Ääniefektit:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Erikoisefektit"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Ääniefektit:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Puhe:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Puhe:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr ""
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Teemojen polku:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Teemojen polku:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Määrittää polun, jossa on lisätiedostoja joita ScummVM tai kaikki pelit "
"käyttävät"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Pluginien sijainti:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Pluginien sijainti:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Muut"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Teema"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI renderöijä:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autom. tallennus:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autom. tallennus:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Näppäimet"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "ScummVM:n kieli:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "ScummVM käyttöliittymän kieli"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "ScummVM pitää käynnistää uudelleen jotta muutokset tulevat voimaan."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Valittuun hakemistoon ei voi kirjoittaa. Valitse toinen hakemisto."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Valitse hakemisto käyttöliittymän teemoille"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Valitse hakemisto lisätiedostoille"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Valitse hakemisto plugineille"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1096,68 +1110,68 @@ msgstr ""
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Poista"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr ""
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Poista"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
#, fuzzy
msgid "Playback"
msgstr "Pelaa"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr ""
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr ""
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr ""
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
#, fuzzy
msgid "Do you really want to delete this record?"
msgstr "Haluatko varmasti poistaa tämän pelitallennuksen?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
#, fuzzy
msgid "Unknown Author"
msgstr "Tuntematon virhe"
@@ -1222,7 +1236,7 @@ msgstr "Luo uusi pelitallennus"
msgid "Name: "
msgstr "Nimi: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Anna kuvaus tallennukselle numero %d:"
@@ -1231,67 +1245,88 @@ msgstr "Anna kuvaus tallennukselle numero %d:"
msgid "Select a Theme"
msgstr "Valitse teema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Disabloitu GFX"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Disabloitu GFX"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
#, fuzzy
msgid "Standard Renderer"
msgstr "Standardirenderöijä (16 bpp)"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standardi"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
#, fuzzy
msgid "Antialiased Renderer"
msgstr "Antialiasoitu renderöijä (16 bpp)"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
#, fuzzy
msgid "Antialiased"
msgstr "Antialiasoitu (16 bpp)"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Tarkista päivitykset..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Tyhjennä arvo"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Pelimoottori ei tue debug tasoa '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Valikko"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Ohita"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Tauko"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Ohita rivi"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Virhe ajettaessa peliä:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Pelimoottoria joka tukisi valittua peliä ei löytynyt"
@@ -1386,17 +1421,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr ""
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Tyhjennä arvo"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Peli hakemistossa '%s' näyttäisi olevan tuntematon."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Ole hyvä ja ilmoita ScummVM:n kehittäjille seuraavat tiedot, lisäksi kerro"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr ""
"mikä peli oli kyseessä, ja sen versio, kieli, ja muut vastaavat tiedot."
@@ -1405,11 +1457,11 @@ msgstr ""
msgid "~R~esume"
msgstr "~J~atka"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~L~ataa"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~T~allenna"
@@ -1434,15 +1486,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Palaa p~e~livalitsimeen"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Tallenna peli:"
@@ -1451,15 +1503,16 @@ msgstr "Tallenna peli:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Tallenna"
@@ -1481,13 +1534,13 @@ msgstr ""
"Pelitilan tallennus epäonnistui (%s)! Avaa LUEMINUT tiedosto saadaksesi "
"lisätietoa."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~H~yväksy"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~P~eruuta"
@@ -1495,23 +1548,23 @@ msgstr "~P~eruuta"
msgid "~K~eys"
msgstr "~N~äppäimet"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Väriformaattia ei voitu alustaa"
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Videotilan vaihto ei onnistunut:'"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kuvasuhdeasetusta ei voitu asettaa."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kokoruututila-asetusta ei voi asettaa."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1524,7 +1577,7 @@ msgstr ""
"pelin tiedostot kovalevyllesi. Avaa LUEMINUT\n"
"tiedosto ohjeita varten."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1537,7 +1590,7 @@ msgstr ""
"ohjelmistoa käyttäen, jotta musiikit\n"
"kuuluvat. Lue ohjeet LUEMINUT tiedostosta."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1546,7 +1599,7 @@ msgstr ""
"Pelitilan lataus epäonnistui (%s)! Avaa LUEMINUT tiedosto saadaksesi "
"lisätietoa."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1556,11 +1609,11 @@ msgstr ""
"epävakaa, eivätkä pelitallennukset välttämättä toimi tulevissa ScummVM:n "
"versioissa."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Pelaa silti"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib emulaattori"
@@ -1642,11 +1695,11 @@ msgstr ""
msgid "PC-98 Audio"
msgstr "Ääni"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Alustetaan MT-32 emulaattoria"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 emulaattori"
@@ -1678,7 +1731,7 @@ msgstr "Haluatko varmasti lopettaa?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Lopeta"
@@ -1765,12 +1818,12 @@ msgstr ""
msgid "Swipe three fingers to the right to toggle."
msgstr ""
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
#, fuzzy
msgid "OpenGL"
msgstr "Avaa"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr ""
@@ -1785,19 +1838,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normaali (ei skaalausta)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Kuvasuhteen korjaus päällä"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Kuvasuhteen korjaus pois päältä"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Valittu grafiikkafiltteri:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Ikkunoitu tila"
@@ -1830,7 +1883,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~S~ulje"
@@ -2327,20 +2380,38 @@ msgstr ""
"Muista määritellä näppäin työkalupalkin piilottamiselle, jotta voit nähdä "
"koko tavaraluettelon"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Tarkista päivitykset..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Klikkaus moodi"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Näytä esineiden tiedot"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Käytä alkuperäisiä tallenna/lataa valikkoja"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Käytä alkuperäisiä tallenna/lataa valikkoja, ScummVM valikoiden sijaan"
@@ -2366,27 +2437,45 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr ""
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Lataa pelitallenne:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Lataa tallenne"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2397,7 +2486,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2408,7 +2497,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2419,7 +2508,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Videotiedostoa '%s' ei löytynyt!"
@@ -2450,20 +2539,20 @@ msgstr ""
"Mikäli et halua muuntaa tiedostoja nyt\n"
"ScummVM kysyy asiaa seuraavan kerran kun käynnistät pelin.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Käytä kirkaspalettitilaa"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Näytä grafiikat käyttäen pelin kirkasta palettia"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Pelitallenteen lataaminen tiedostosta epäonnistui."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Pelin tallentaminen tiedostoon epäonnistui."
@@ -2481,7 +2570,7 @@ msgstr "Nopea moodi"
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Pelin tallentaminen epäonnistui."
@@ -2640,49 +2729,59 @@ msgid ""
"\n"
msgstr ""
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ip moodi valittu"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "Siirtymät päällä"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "Pudota sivu"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "Näytä kartta"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "Päävalikko"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "Vesiefekti päällä"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr ""
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2691,25 +2790,25 @@ msgstr ""
"Pelin tallennus kohtaan ei onnistunut kohtaan %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
#, fuzzy
msgid "Load file"
msgstr "Lataa peli:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Ladataan peliä..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
#, fuzzy
msgid "Save file"
msgstr "Tallenna peli:"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Tallennetaan peliä..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2725,11 +2824,11 @@ msgstr ""
"Jos et tee muunnosta nyt, ScummVM kysyy sinulta uudelleen seuraavalla "
"kerralla kun käynnistät pelin.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM muunsi kaikki pelitallenteet onnistuneesti"
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2785,186 +2884,204 @@ msgstr "Vaihtoehtoinen intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "Käytä vaihtoehtoista pelin introa (vain CD versiossa)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
#, fuzzy
msgid "Enable high resolution graphics"
msgstr "Käytä kestopisteissä värillisiä grafiikkapalkkeja numeroiden sijaan"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
#, fuzzy
msgid "Enable high resolution graphics/content"
msgstr "Käytä kestopisteissä värillisiä grafiikkapalkkeja numeroiden sijaan"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Käytä Roland GS moodia"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Käytä mieluiten digitaalisia äänitehosteita."
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
"Käytä mieluiten digitaalisia äänitehosteita synteettisten tehosteiden sijaan."
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Käytä IMF/Yamaha FB-01:stä MIDI-musiikille"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
msgstr ""
"Käytä IBM:n Music Feature korttia, tai Yamaha FB-01 FM moduulia MIDIlle"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Käytä CD:n ääntä"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Käytä CD:n audiota pelin audion sijaan, jos mahdollista."
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Käytä Windowsin kursoreita"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Käytä Windowsin kursoreita (pienempiä ja harmaasävyisiä) DOS kursorien sijaan"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Käytä hopeisia kursoreita"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr "Käytä vaihtoehtoisia hopeisia kursoreita normaalien kultaisten sijaan"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Näytä esineiden tiedot"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Lisää levyke %c ja paina jotain nappia jatkaaksesi."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Tiedosto %s, (%c%d) ei löydy. Paina nappia."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Virhe luettaessa levyä %c, (%c%d) Paina jotain nappia."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Pause. Paina välilyöntiä jatkaaksesi."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
#, fuzzy
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Haluatko varmasti aloittaa pelin alusta? (K/E)K"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
#, fuzzy
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Haluatko varmati lopettaa?"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Pelaa"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Laita tallennus/lataus levy asemaan"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Nimi on pakko antaa"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Peliä EI tallennettu (onko levy täysi?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Peliä EI ladattu"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Tallennetaan '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Ladataan '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Nimeä pelitallenteesi"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Valitse ladattava peli"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Pelin nimi"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "E~d~ellinen"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "Se~u~raava"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Vain puhe"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Puhe ja Tekstitys"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Vain tekstitys"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Puhe & teksti"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Valitse taitotasosi."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Lue Loom(TM) ohjekirjaa saadaksesi ohjeita."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Harjoitus"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspertti"
@@ -3501,26 +3618,26 @@ msgstr "Lennä oikealle"
msgid "Fly to lower right"
msgstr "Lennä alas oikealle"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
#, fuzzy
msgid "Snap scroll on"
msgstr "Pehmeä vieritys"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
#, fuzzy
msgid "Music volume: "
msgstr "Musiikki:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
#, fuzzy
msgid "Subtitle speed: "
msgstr "Tekstin nopeus:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3529,7 +3646,7 @@ msgstr ""
"Suora MIDI tuki vaatii Roland päivityksen LucasArtsilta, mutta\n"
"%s puuttuu. Käytetään AdLibia sen sijaan."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
#, fuzzy
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
@@ -3702,14 +3819,23 @@ msgstr "Näytä esineiden tiedot"
msgid "Show labels for objects on mouse hover"
msgstr "Näytä esineiden kuvaus kohdistaessasi kursorin esineen ylle"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"Asennuksestasi puuttuu 'teenagent.dat' tiedosto. Hae se ScummVM:n "
"nettisivuilta"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3809,6 +3935,3 @@ msgstr "Käytä vaihtoehtoisia hopeisia kursoreita normaalien kultaisten sijaan"
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Valittu filtteritila: Nearest"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Käytä Roland GS moodia"
diff --git a/po/fr_FR.po b/po/fr_FR.po
index e223a96a54..a6f3a1f35f 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-20 23:17+0000\n"
"Last-Translator: Thierry Crozat <criezy@scummvm.org>\n"
"Language-Team: French <scummvm-devel@lists.sf.net>\n"
@@ -54,15 +54,16 @@ msgstr "Remonter"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Annuler"
@@ -101,7 +102,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Voulez-vous vraiment remplacer ce fichier ?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -111,7 +112,7 @@ msgid "Yes"
msgstr "Oui"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -172,7 +173,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Triangle"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Divers"
@@ -204,14 +205,14 @@ msgstr "Réinitialiser"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Remet tous les réglages à leurs valeurs par défaut."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -240,15 +241,15 @@ msgstr "Fermer"
msgid "Mouse click"
msgstr "Clic de souris"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Afficher le clavier"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Changer l'affectation des touches"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Basculer en plein écran"
@@ -324,8 +325,8 @@ msgstr ""
"Langue du jeu. Cela ne traduira pas en anglais par magie votre version "
"espagnole du jeu."
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<defaut>"
@@ -347,11 +348,11 @@ msgstr "Système :"
msgid "Engine"
msgstr "Moteur"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Graphique"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -364,7 +365,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Réglages spécifiques à ce jeux"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Audio"
@@ -377,11 +378,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Réglages spécifiques à ce jeux"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volume"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volume"
@@ -395,217 +396,218 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Réglages spécifiques à ce jeux"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Utiliser des réglages MIDI spécifiques à ce jeux"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Réglages spécifiques à ce jeux"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Utiliser des réglages MT-32 spécifiques à ce jeux"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Réglages spécifiques à ce jeux"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Chemins"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Chemins"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Chemin du Jeu :"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Chemin du Jeu :"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Extra :"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Définie un chemin vers des données suplémentaires utilisées par le jeu"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Extra :"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Sauvegardes :"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Définie l'emplacement où les fichiers de sauvegarde sont créés"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Sauvegardes :"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Aucun"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Défaut"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Choisir une banque de sons"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Sélectionner le répertoire contenant les données du jeu"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Sélectionner un répertoire supplémentaire"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Sélectionner le répertoire pour les sauvegardes"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Cet ID est déjà utilisé par un autre jeu. Choisissez en un autre svp."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~Q~uitter"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Quitter ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "À ~P~ropos..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "À propos de ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~ptions..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Change les options globales de ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~D~émarrer"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Démarre le jeu sélectionné"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~C~harger"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Charge une sauvegarde pour le jeu sélectionné"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~A~jouter..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr ""
"Ajoute un jeu à la Liste. Maintenez Shift enfoncée pour un Ajout Massif"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~diter..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Change les options du jeu"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~S~upprimer"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Supprime le jeu de la liste. Les fichiers sont conservés"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~A~jouter..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~diter..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~S~upprimer"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Recherche dans la liste de jeux"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Filtre :"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Charger le jeu :"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Charger"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -613,40 +615,40 @@ msgstr ""
"Voulez-vous vraiment lancer la détection automatique des jeux ? Cela peut "
"potentiellement ajouter un grand nombre de jeux."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM n'a pas pu ouvrir le répertoire sélectionné."
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM n'a pas trouvé de jeux dans le répertoire sélectionné."
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Choisissez le jeu :"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Voulez-vous vraiment supprimer ce jeu ?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Voulez-vous charger le jeu ?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr ""
"Le chargement de sauvegarde depuis le lanceur n'est pas supporté pour ce jeu."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM n'a pas pu trouvé de moteur pour lancer le jeu sélectionné."
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Ajout Massif..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Enregistrer..."
@@ -690,134 +692,134 @@ msgstr "Retourner au jeu"
msgid "Fast replay"
msgstr "Rejouer rapidement"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Jamais"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "Toutes les 5 mins"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "Toutes les 10 mins"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "Toutes les 15 mins"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "Toutes les 30 mins"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Aucune"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Certaines options graphiques n'ont pu être changées :"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "le mode vidéo n'a pu être changé."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "le mode plein écran n'a pu être changé."
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "la correction de rapport d'aspect n'a pu être changée."
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Mode graphique :"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Mode de rendu :"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Mode spécial de tramage supporté par certains jeux"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Plein écran"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Correction du rapport d'aspect"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Corrige le rapport d'aspect pour les jeu 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Sortie Préféré :"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Sortie Audio :"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
"Spécifie le périphérique de sortie audio ou l'émulateur de carte audio "
"préféré"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Spécifie le périphérique de sortie audio ou l'émulateur de carte audio"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Sortie Préféré :"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Sortie Audio :"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Émulateur AdLib :"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib est utilisé pour la musique dans de nombreux jeux"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Fréquence :"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -825,68 +827,64 @@ msgstr ""
"Une valeur plus élevée donne une meilleure qualité audio mais peut ne pas "
"être supporté par votre carte son"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Sortie GM :"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Spécifie le périphérique audio par défaut pour la sortie General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Ne pas utiliser la musique General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Utiliser le premier périphérique disponible"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "Banque de sons :"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"La banque de sons (SoundFont) est utilisée par certaines cartes audio, "
"FluidSynth et Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont :"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Mode mixe AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Utiliser à la fois MIDI et AdLib"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Gain MIDI :"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Paramètres FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Sortie MT-32 :"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Spécifie le périphérique audio par défaut pour la sortie Roland MT-32/LAPC1/"
"CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 exacte (désactive l'émulation GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -894,16 +892,16 @@ msgstr ""
"Vérifie si vous voulez utiliser un périphérique audio compatible Roland "
"connecté à l'ordinateur"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 exacte (pas d'ému GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS (active le mappage MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -911,174 +909,190 @@ msgstr ""
"Utilisez cette option si vous voulez activez le mappage à la volée pour une "
"émulation MT-32 sur un appareil Roland GS."
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Ne pas utiliser la musique Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Dialogue :"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Voix"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Sous-titres"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Les deux"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Vitesse des ST :"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Dialogue :"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Voix"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Subs"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "V&S"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Affiche les sous-titres et joue les dialogues audio"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Vitesse des ST :"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Volume Musique :"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musique :"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Silence"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Volume Bruitage :"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volume des effets spéciaux sonores"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Bruitage :"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Volume Dialogues :"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Dialogues :"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Paramètres FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Thèmes :"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Thèmes :"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Spécifie un chemin vers des données supplémentaires utilisées par tous les "
"jeux ou ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Plugins :"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Plugins :"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Divers"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Thème :"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Interface :"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Sauvegarde auto :"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Sauvegarde :"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Touches"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Langue :"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Langue de l'interface graphique de ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "Vérif. mises à jour :"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "Fréquence des vérifications"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "Maintenant"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr ""
"Vous devez relancer ScummVM pour que le changement soit pris en compte."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
"Le répertoire sélectionné est vérouillé en écriture. Sélectionnez un autre "
"répertoire."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Sélectionner le répertoire des thèmes d'interface"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Sélectionner le répertoire pour les fichiers suplémentaires"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Sélectionner le répertoire des plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1095,65 +1109,65 @@ msgstr "# suivant"
msgid "add"
msgstr "ajouter"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Supprimer le caractère"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pré"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* 123"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Enregistreur ou Joueur de Gameplay"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Supprimer"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Enregistrer"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Lecture"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Editer"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Auteur : "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notes : "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Voulez-vous vraiment supprimer cet enregistrement ?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Auteur inconnu"
@@ -1217,7 +1231,7 @@ msgstr "Crée une nouvelle sauvegarde."
msgid "Name: "
msgstr "Nom: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Entrez une description pour l'emplacement %d:"
@@ -1226,64 +1240,90 @@ msgstr "Entrez une description pour l'emplacement %d:"
msgid "Select a Theme"
msgstr "Sélectionnez un Thème"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX désactivé"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX désactivé"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Rendu Standard"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Normal"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Rendu Anti-crénelé"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Anti-crénelé"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM peut maintenant rechercher les mises à jour\n"
+"automatiquement, ce qui necessite un accès internet.\n"
+"\n"
+"Voulez-vous activer cette options?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+"(Vous pouvez aussi activer cette option dans le tab 'Divers'\n"
+"du dialogue d'options)"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Vérifier les mises à jour automatiquement"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Appliquer"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Effacer la valeur"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Le niveau de debug '%s' n'est pas supporté par ce moteur de jeu"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Passer"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Mettre en pause"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Passer la phrase"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Erreur lors de l'éxécution du jeu : "
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Impossible de trouver un moteur pour exécuter le jeu sélectionné"
@@ -1378,18 +1418,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Ambre"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "Une fois par jour"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "Une fois pas semaine"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "Une fois pas mois"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<Valeur invalide>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Le jeu dans '%s' n'est pas reconnu."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Veuillez reporter les informations suivantes à l'équipe ScummVM ainsi que le "
"nom"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "du jeu que vous avez essayé d'ajouter, sa version, le langage, etc..."
@@ -1397,11 +1453,11 @@ msgstr "du jeu que vous avez essayé d'ajouter, sa version, le langage, etc..."
msgid "~R~esume"
msgstr "~R~eprendre"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~C~harger"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~S~auver"
@@ -1426,15 +1482,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Retour au ~L~anceur"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Sauvegarde :"
@@ -1443,15 +1499,16 @@ msgstr "Sauvegarde :"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Sauver"
@@ -1474,13 +1531,13 @@ msgstr ""
"Echec de la sauvegarde (%s)! Lisez le fichier README pour les informations "
"de base et les instructions pour obtenir de l'aide supplémentaire."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~nnuler"
@@ -1488,23 +1545,23 @@ msgstr "~A~nnuler"
msgid "~K~eys"
msgstr "~T~ouches"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Impossible d'initialiser le format des couleurs."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Impossible de changer le mode vidéo à: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Impossible d'appliquer la correction du rapport d'aspect."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Impossible d'appliquer l'option plein écran."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1518,7 +1575,7 @@ msgstr ""
"données du jeu sur votre disque dur.\n"
"Lisez le fichier README pour plus de détails."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1532,7 +1589,7 @@ msgstr ""
"logiciel approprié.\n"
"Lisez le fichier README pour plus de détails."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1541,7 +1598,7 @@ msgstr ""
"Echec du chargement (%s) ! Lisez le fichier README pour les informations de "
"base et les instructions pour obtenir de l'aide supplémentaire."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1551,11 +1608,11 @@ msgstr ""
"complètement supporté par ScummVM. Il est donc instable et les sauvegardes "
"peuvent ne pas marcher avec une future version de ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Jouer quand même"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Émulateur AdLib"
@@ -1636,11 +1693,11 @@ msgstr "Audio FM Towns"
msgid "PC-98 Audio"
msgstr "Audio PC-98"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Initialisation de l'Émulateur MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Émulateur MT-32"
@@ -1672,7 +1729,7 @@ msgstr "Voulez-vous vraiment quitter ?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Quitter"
@@ -1757,11 +1814,11 @@ msgstr "Le mode glisser-auto est maintenant"
msgid "Swipe three fingers to the right to toggle."
msgstr "Glissez trois doigts vers la droite pour changer de mode."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (sans filtre)"
@@ -1776,19 +1833,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Activer la correction du rapport d'aspect"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Désactiver la correction du rapport d'aspect"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Mode graphique actif:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Mode Fenêtre"
@@ -1821,7 +1878,7 @@ msgid "Windows MIDI"
msgstr "MIDI Windows"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~F~ermer"
@@ -2315,20 +2372,36 @@ msgstr ""
"Noubliez pas d'affecter une touche à l'action 'Cacher Bar d'Outils' pour "
"pouvoir voir entièrement l'inventaire"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Recherche des mises à jour..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Mode Couleurs"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Utiliser les graphiques en couleurs"
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "Tracé par ligne"
+
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Afficher le tracé par ligne"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Dialogues sauvegarde/chargement d'origine"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2358,27 +2431,48 @@ msgstr ""
"Activer le support de la souris. Cela permet d'utiliser la souris pour les "
"mouvements et la navigation dans les menus."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "Utiliser les polices Hercules haute résolution"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+"Utilise les polices Hercules haute résolution quand elles sont disponibles."
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "Pause lors de la saisie de commandes"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"Affiche une fenêtre de saisie de commandes et interrompt le jeu (comme pour "
+"les jeux SCI) à la place d'un champ de saisie en temps réel."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Charger le jeu :"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Charger"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2389,7 +2483,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2400,7 +2494,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2411,7 +2505,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Fichier de séquence '%s' non trouvé !"
@@ -2442,20 +2536,20 @@ msgstr ""
"Appuyer sur OK pour les convertir maintenant, sinon le même message "
"s'affichera la prochaine fois que vous démarrerez le jeu.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Utiliser le mode palette lumineuse"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Utiliser la palette lumineuse du jeu pour l'affichage"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Échec du chargement de l'état du jeu depuis le disque."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Échec de l'enregistrement de l'état du jeu sur le disque."
@@ -2472,7 +2566,7 @@ msgstr "Vidéo rapide"
msgid "Play movies at an increased speed"
msgstr "Joue les vidéos plus rapidement"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Échec de la sauvegarde."
@@ -2647,52 +2741,60 @@ msgstr ""
"\n"
" \n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "Jouer la vidéo du survol de Myst"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr "La vidéo du survol de Myst n'était pas jouée par le moteur originel."
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "Mode ~Z~ip Activé"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "T~r~ansitions activées"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~L~acher la Page"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
-msgstr "Afficher la Carte"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
+msgstr "Afficher la ~C~arte"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
msgstr "~M~enu Principal"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~E~ffets de l'Eau Activés"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Sauter les scènes storyboard de la Salle des Archives"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Permet au joueur de sauter les scènes de storyboard de la Salle des Archives."
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Afficher les vidéos du 'making of' en plein écran."
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
"Redimensionne les vidéos du 'making of' pour qu'elles s'affichent en plein "
"écran."
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2701,23 +2803,23 @@ msgstr ""
"Erreur lors de la sauvegarde dans l'emplacement %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Charger une partie"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Chargement en cours..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Sauver une partie"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Sauvegarde en cours..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2734,11 +2836,11 @@ msgstr ""
"Appuyer sur OK pour les convertir maintenant, sinon le même message "
"s'affichera la prochaine fois que vous démarrerez le jeu.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM a converti avec succès vos anciennes sauvegardes."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2792,37 +2894,46 @@ msgstr "Intro alternative"
msgid "Use an alternative game intro (CD version only)"
msgstr "Utiliser une intro alternative (version CD uniquement)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Passer l'étape de tramage EGA (fonds de couleurs pleines)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Passer l'étape de tramage dans les jeux EGA ; les images utilisent des "
"couleurs pleines"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Utiliser les graphiques haute résolution"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Utiliser les graphiques haute résolution"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Activer le mode Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Préférer les effets sonores digitaux"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Préférer les effets sonores digitaux plutôt que ceux synthétisés"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Utiliser IMF/Yamaha FB-01 pour la sortie MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2830,149 +2941,157 @@ msgstr ""
"Utiliser une carte IBM Music Feature ou un module Yamaha FB-01 FM pour la "
"sortie MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Utiliser la musique du CD"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"Utiliser la musique du CD quand elle est disponible au lieu de la musique du "
"jeu"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Utiliser les curseurs Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Utiliser les curseurs Windows (plus petits et monochromes) au lieu des "
"curseurs DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Utiliser les curseurs argentés"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr "Utiliser les curseurs argentés au lieu des curseurs normaux dorés"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "Afficher la barre d'objets"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "Afficher le nom des objets en bas de l'écran"
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Insérer le Disque %c et appuyer sur le Bouton pour Continuer."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Impossible de trouver %s, (%c%d) Appuyer sur le Bouton."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Erreur lors de la lecture du disque %c, (%c%d). Appuyer sur le Bouton."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Jeu en pause. Appuyer sur Espace pour Reprendre."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Voulez-vous vraiment recommencer ? (O/N)O"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Voulez-vous vraiment quitter ? (O/N)O"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Jouer"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Insérer le disque de sauvegarde/chargement"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Vous devez entrer un nom"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Le jeu n'a pu être sauvé (disque plein ?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Le jeu n'a pu être chargé"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Sauvegarde de '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Chargement de '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Donnez un nom à votre sauvegarde"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Sélectionnez un jeu à charger"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Nom du jeu)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~P~récédent"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~S~uivant"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Voix"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voix et Sous-titres"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Sous-titres"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voix & ST"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Sélectionnez un niveau de compétence."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Reportez-vous à votre manuel d'instruction."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Essai"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3509,23 +3628,23 @@ msgstr "Voler vers la droite"
msgid "Fly to lower right"
msgstr "Voler vers la bas à droite"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Défilement par à-coups"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Défilement régulier"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Volume Musique :"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Vitesse des ST :"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3534,7 +3653,7 @@ msgstr ""
"Support MIDI natif requière la mise à jour Roland de LucasArt,\n"
"mais %s manque. Utilise AdLib à la place."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3723,14 +3842,25 @@ msgstr "Afficher la description des objets"
msgid "Show labels for objects on mouse hover"
msgstr "Afficher la description des objets lors de passage du pointeur"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "Utiliser les voix anglaises"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+"Utilise les voix anglaises au lieu des voix allemandes pour tous les autres "
+"langages"
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"Il vous manque le fichier 'teenagent.dat'. Téléchargez le depuis le site web "
"de ScummVM."
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3833,9 +3963,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Filtre actif: Plus proche"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Activer le mode Roland GS"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Ajouter..."
diff --git a/po/gl_ES.po b/po/gl_ES.po
index 22b99fe2a7..c4a4dfb198 100644
--- a/po/gl_ES.po
+++ b/po/gl_ES.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.8.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-21 00:43+0100\n"
"Last-Translator: Santiago G. Sanz <s.sanz@uvigo.es>\n"
"Language-Team: Santiago G. Sanz <s.sanz@uvigo.es>\n"
@@ -53,15 +53,16 @@ msgstr "Arriba"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Cancelar"
@@ -100,7 +101,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Seguro que queres sobreescribir o ficheiro?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -110,7 +111,7 @@ msgid "Yes"
msgstr "Si"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -171,7 +172,7 @@ msgstr "Seno"
msgid "Triangle"
msgstr "Triángulo"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Misc."
@@ -204,14 +205,14 @@ msgid "Reset all FluidSynth settings to their default values."
msgstr ""
"Restablece a configuración de FluidSynth aos seus valores predefinidos."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -241,15 +242,15 @@ msgstr "Pechar"
msgid "Mouse click"
msgstr "Premer co rato"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostrar teclado"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Asignar teclas"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Activar/desactivar pantalla completa"
@@ -323,8 +324,8 @@ msgid ""
"English"
msgstr "Idioma do xogo. Non converterá a versión galega do xogo en inglesa"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<por defecto>"
@@ -346,11 +347,11 @@ msgstr "Plataforma:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Gráficos"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "Efectos gráficos"
@@ -363,7 +364,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Anular a configuración dos gráficos"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Son"
@@ -376,11 +377,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Anular a configuración do son"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volume"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volume"
@@ -394,216 +395,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Anular a configuración do volume"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Anular a configuración de MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Anular a configuración de MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Anular a configuración de MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Anular a configuración de MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Camiños"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Camiños"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Camiño do xogo:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Camiño do xogo:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Camiño adicional:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Especifica o camiño dos datos adicionais usados no xogo"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Camiño adicional:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Camiño de gardado:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Especifica o lugar dos ficheiros de gardado"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Camiño de gardado:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ningún"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Predefinido"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Seleccionar SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Selecciona un directorio con datos de xogo"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Selecciona un directorio con datos adicionais"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Selecciona un directorio para ficheiros de gardado"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Este ID de xogo xa está en uso. Selecciona outro."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~S~aír"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Saír de ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "Ace~r~ca de..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Acerca de ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pcións..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Cambiar as opcións de ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~I~niciar"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Iniciar o xogo seleccionado"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~C~argar..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Cargar partida do xogo seleccionado"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "Eng~a~dir xogo..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Manter premido MAIÚS para engadir en masa"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~ditar xogo..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Cambiar as opcións do xogo"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "Elimina~r~ xogo"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Eliminar o xogo da lista. Os ficheiros de datos non se modifican"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "Eng~a~dir xogo..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~ditar xogo..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "Elimina~r~ xogo"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Buscar na lista de xogos"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Buscar:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Cargar partida:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Cargar"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -611,39 +613,39 @@ msgstr ""
"Queres executar o detector de xogos en masa? É posible que se engada un gran "
"número de xogos."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM non foi quen de abrir o directorio!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM non foi quen de atopar xogos no directorio!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Elixe o xogo:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Seguro que queres eliminar esta configuración de xogo?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Queres cargar a partida gardada?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "O xogo non permite cargar partidas dende o iniciador."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM non foi quen de atopar un motor para executar o xogo!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Engadir en masa..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Gravar..."
@@ -686,132 +688,132 @@ msgstr "Cambiar ao xogo"
msgid "Fast replay"
msgstr "Repetición rápida"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Nunca"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "cada 5 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "cada 10 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "cada 15 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "cada 30 min"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ningunha"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Erro ao aplicar os cambios na configuración dos gráficos:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "non se puido cambiar o modo de vídeo."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "non se puido cambiar a configuración de pantalla completa."
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "non se puido cambiar a proporción."
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Gráficos:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Procesamento:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Modos de interpolación de cores compatibles con algúns xogos"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Pantalla completa"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Corrección de proporción"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Corrixir a proporción para os xogos en 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Dispositivo preferido:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Dispositivo de música:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Especifica o dispositivo ou emulador de tarxeta de son preferido"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Especifica o dispositivo ou emulador de tarxeta de son de saída"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Disp. preferido:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Disp. música:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Emulador de AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "Moitos xogos empregan AdLib para a música"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Taxa de saída:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -819,84 +821,80 @@ msgstr ""
"A maior valor, maior calidade do son, mais talvez non sexa compatible coa "
"tarxeta"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Dispositivo de GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr ""
"Especifica o dispositivo de son por defecto para a saída de General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Non empregar música en General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Empregar o primeiro dispositivo dispoñible"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont é compatible con algunhas tarxetas de son, FluidSynth e Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Modo AdLib/MIDI mixto"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Empregar xeración de son MIDI e máis AdLib"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Ganancia de MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Configuración de FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Dispositivo de MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Especifica o dispositivo por defecto para a saída de Roland MT-32/LAPC1/"
"CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 verdadeiro (sen emulación de GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
msgstr ""
"Marcar para empregar o hardware compatible con Roland conectado ao sistema"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 (sen emulación de GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Dispositivo Roland GS (activar atribución MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -904,170 +902,186 @@ msgstr ""
"Marcar para activar a atribución de parches e emular MT-32 nun dispositivo "
"Roland GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Non empregar música en Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Texto e voz:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Voz"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Subtítulos"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Ambos"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Velocidade dos subtítulos:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Texto e voz:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Voz"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Subs"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Ambos"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Mostrar os subtítulos e reproducir as voces"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Velocidade subs:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Volume de música:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Volume música:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Silenciar todo"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Volume de efectos:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volume dos efectos de son"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Volume efectos:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Volume de voz:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Volume voz:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Configuración de FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Camiño do tema:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Camiño tema:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Especificar o camiño dos datos adicionais de todos os xogos ou de ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Camiño dos complementos:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Camiño complementos:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Misc."
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Procesamento da interfaz:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autogardado:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autogardado:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Teclas"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Idioma de interfaz:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Idioma da interfaz de ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Debes reiniciar ScummVM para que os cambios teñan efecto."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Non é posible escribir no directorio elixido. Selecciona outro."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Seleccionar directorio para temas de interfaz"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Seleccionar directorio para ficheiros adicionais"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Seleccionar directorio para complementos"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1084,65 +1098,65 @@ msgstr "# seguinte"
msgid "add"
msgstr "engadir"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Eliminar carácter"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Núm"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Partida gravada ou reproducida"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Eliminar"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Gravar"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Reproducir"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Editar"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Autor:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notas:"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Seguro que queres eliminar esta gravación?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Autor descoñecido"
@@ -1206,7 +1220,7 @@ msgstr "Crea un novo ficheiro de gardado"
msgid "Name: "
msgstr "Nome:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Introduce unha descrición para o espazo %d:"
@@ -1215,64 +1229,85 @@ msgstr "Introduce unha descrición para o espazo %d:"
msgid "Select a Theme"
msgstr "Seleccionar tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Efectos gráficos desactivados"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Efectos desactivados"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Procesamento estándar"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Estándar"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Procesamento antidistorsión"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Antidistorsión"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Buscar actualizacións..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Limpar valor"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "O motor non é compatible co nivel de depuración %s"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menú"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Omitir"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pausa"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Omitir liña"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Erro de execución do xogo:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Non se puido atopar un motor para executar o xogo seleccionado"
@@ -1367,16 +1402,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules ámbar"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Limpar valor"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "O xogo de %s semella ser descoñecido."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Facilita esta información ao equipo de ScummVM, xunto co nome"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "do xogo que tentaches engadir, xunto coa versión, lingua, etc.:"
@@ -1384,11 +1436,11 @@ msgstr "do xogo que tentaches engadir, xunto coa versión, lingua, etc.:"
msgid "~R~esume"
msgstr "~R~etomar"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~C~argar"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~G~ardar"
@@ -1413,15 +1465,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~olver ao Iniciador"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Gardar partida:"
@@ -1430,15 +1482,16 @@ msgstr "Gardar partida:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Gardar"
@@ -1461,13 +1514,13 @@ msgstr ""
"Erro ao gardar (%s)! Consulta o ficheiro README para obter información "
"básica e máis instrucións para acadar asistencia adicional."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~A~ceptar"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~C~ancelar"
@@ -1475,23 +1528,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Non se puido iniciar o formato de cor."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Non se puido cambiar ao modo de vídeo: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Non se puido aplicar a configuración de proporción."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Non se puido aplicar a configuración de pantalla completa."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1505,7 +1558,7 @@ msgstr ""
"os ficheiros de datos ao disco duro. Consulta\n"
"o ficheiro README para obter máis información."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1519,7 +1572,7 @@ msgstr ""
"do xogo. Consulta o ficheiro README\n"
"para obter máis información."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1528,7 +1581,7 @@ msgstr ""
"Erro ao cargar (%s)! Consulta o ficheiro README para obter información "
"básica e máis instrucións para acadar asistencia adicional."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1538,11 +1591,11 @@ msgstr ""
"Por iso, talvez sexa inestable e os ficheiros de gardado talvez non "
"funcionen en futuras versións de ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Iniciar de todos os xeitos"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Emulador de AdLib"
@@ -1623,11 +1676,11 @@ msgstr "FM-Towns Audio"
msgid "PC-98 Audio"
msgstr "PC-98 Audio"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Iniciando emulador de MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Emulador de MT-32"
@@ -1659,7 +1712,7 @@ msgstr "Seguro que queres saír?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Saír"
@@ -1744,11 +1797,11 @@ msgstr "O modo Autoarrastrar está"
msgid "Swipe three fingers to the right to toggle."
msgstr "Arrastra tres dedos á dereita para cambiar o estado."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (Sen filtraxe)"
@@ -1763,19 +1816,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (sen escala)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Corrección de proporción activada"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Corrección de proporción desactivada"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Filtro de gráficos activo:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Modo en ventá"
@@ -1808,7 +1861,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~P~echar"
@@ -2300,20 +2353,38 @@ msgstr ""
"Non esquezas asignar unha tecla á acción Ocultar barra de ferramentas para "
"ver o inventario completo"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Buscar actualizacións..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Modo accesible para daltonismo"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostrar etiquetas"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Empregar pantallas orixinais de gardado e carga"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2342,27 +2413,46 @@ msgstr ""
"Activa a compatibilidade co rato. Permite o uso do rato para o movemento e "
"os menús do xogo."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules verde"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Restaurar xogo:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Restaurar"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2373,7 +2463,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2384,7 +2474,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2395,7 +2485,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Non se atopou o ficheiro de secuencia %s!"
@@ -2426,20 +2516,20 @@ msgstr ""
"Preme Aceptar para convertilos. Se non, volverás ver esta mensaxe a próxima "
"vez que inicies o xogo.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Empregar modo Paleta intensa"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Mostrar os gráficos coa paletta intensa do xogo"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Erro ao cargar a partida do ficheiro."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Erro ao gardar a partida no ficheiro."
@@ -2456,7 +2546,7 @@ msgstr "Velocidade de vídeo rápida"
msgid "Play movies at an increased speed"
msgstr "Reproducir vídeos a máis velocidade"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Erro ao gardar a partida"
@@ -2631,49 +2721,59 @@ msgstr ""
"\".\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "Modo ~C~omprimido activado"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~T~ransicións activadas"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~D~eixar folla"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "Mo~s~trar mapa"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~M~enú principal"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "Efecto de ~a~uga activado"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Omitir as escenas do Salón dos rexistros"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "Permite ao xogador saltar as escenas do Salón dos rexistros"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Redimensionar vídeos a pantalla completa"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Redimensionar a creación de vídeos en pantalla completa"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2682,23 +2782,23 @@ msgstr ""
"Non se pode gardar a partida no espazo %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Cargar ficheiro"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Cargando..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Gardar ficheiro"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Gardando..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2715,11 +2815,11 @@ msgstr ""
"Preme Aceptar para cambialos. Se non, volverás ver esta mensaxe a próxima "
"vez que inicies o xogo.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM converteu correctamente todos os ficheiros de gardado."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2775,37 +2875,46 @@ msgstr "Intro alternativa"
msgid "Use an alternative game intro (CD version only)"
msgstr "Emprega unha introdución alternativa para o xogo (só versión en CD)."
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Omitir interpolación de cores EGA (fondos de cor completa)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Omite a interpolación de cores EGA. Os gráficos móstranse con cores "
"completas."
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Activar gráficos de alta resolución"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Activa os gráficos ou o contido de alta resolución."
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Activar modo Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Preferir efectos de son dixitais"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Dá preferencia aos efectos de son dixitais no canto dos sintéticos."
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Empregar IMF/Yamaha FB-01 para a saída de MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2813,149 +2922,158 @@ msgstr ""
"Emprega unha tarxeta IBM Music Feature ou un módulo de sintetizador Yamaha "
"FB-01 FM para a saída de MIDI."
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Empregar son de CD"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Emprega son de CD no canto do do xogo, de ser o caso."
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Empregar cursores de Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Emprega os cursores de Windows (máis pequenos e monocromos) no canto dos de "
"DOS."
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Empregar cursores prateados"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Emprega o xogo de cursores prateados alternativo, no canto dos dourados "
"normais."
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Mostrar etiquetas"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Insire o disco %c e preme o botón para continuar."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Non se puido atopar %s, (%c%d). Preme o botón."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Erro ao ler o disco %c, (%c%d). Preme o botón."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Xogo en pausa. Pulsa a barra espazadora para continuar."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Seguro que queres reiniciar? (S/N)S"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Seguro que queres saír? (S/N)S"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Xogar"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Inserir disco de gardado/carga"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Debes introducir un nome"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Non se puido gardar a partida (disco cheo?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Non se puido cargar a partida"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Gardando %s"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Cargando %s"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Introduce un nome para a partida gardada"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Selecciona unha partida para cargala"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Título)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~A~nterior"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~S~eguinte"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Só voz"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voz e subtítulos"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Só subtítulos"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voz e subs"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selecciona un nivel de habilidade."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Consulta o manual de Loom(TM) para obter axuda."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Práctica"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Experto"
@@ -3492,23 +3610,23 @@ msgstr "Voar á dereita"
msgid "Fly to lower right"
msgstr "Voar á dereita abaixo"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Axuste de desprazamento SI"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Axuste de desprazamento NON"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Volume de música:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Velocidade dos subtítulos:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3517,7 +3635,7 @@ msgstr ""
"A compatibilidade nativa con MIDI precisa a actualización de Roland\n"
"de LucasArts, mais falla %s. Empregarase AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3700,13 +3818,22 @@ msgstr "Mostrar etiquetas"
msgid "Show labels for objects on mouse hover"
msgstr "Mostra as etiquetas dos obxectos ao apuntar co rato."
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"Falta o ficheiro teenagent.dat. Descárgao dende o sitio web de ScummVM."
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3804,6 +3931,3 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Modo de filtro activo: máis próximo"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Activar modo Roland GS"
diff --git a/po/hu_HU.po b/po/hu_HU.po
index 02878f4fbc..69fc239a21 100644..100755
--- a/po/hu_HU.po
+++ b/po/hu_HU.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
-"PO-Revision-Date: 2016-02-21 06:24+0200\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
+"PO-Revision-Date: 2016-07-20 05:59+0200\n"
"Last-Translator: George Kormendi <grubycza@hotmail.com>\n"
"Language-Team: Hungarian\n"
"Language: Magyar\n"
@@ -54,15 +54,16 @@ msgstr "Feljebb"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Mégse"
@@ -101,7 +102,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Biztos hogy felül akarod írni a fájlt?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -111,7 +112,7 @@ msgid "Yes"
msgstr "Igen"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -172,7 +173,7 @@ msgstr "Színusz"
msgid "Triangle"
msgstr "Háromszög"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Vegyes"
@@ -204,14 +205,14 @@ msgstr "Reset"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Minden FluidSynth beállítás alapértelmezett értékre."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -240,15 +241,15 @@ msgstr "Bezár"
msgid "Mouse click"
msgstr "Egérkattintás"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Billentyûzet beállítások"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Billentyûk átállítása"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Teljesképernyõ kapcsoló"
@@ -322,8 +323,8 @@ msgid ""
msgstr ""
"A játék nyelve. Ne állítsd át a pl. Spanyol nyelvû játékodat Angol nyelvre"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<alapértelmezett>"
@@ -345,11 +346,11 @@ msgstr "Platform:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafika"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -362,7 +363,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Globális grafikai beállítások felülbírálása"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Audió"
@@ -375,11 +376,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Globális audió beállítások felülbírálása"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Hangerõ"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Hangerõ"
@@ -393,216 +394,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Globális hangerõbeállítások felülbírálása"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Globális MIDI beállítások felülbírálása"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Globális MIDI beállítások felülbírálása"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Globális MT-32 beállítások felülbírálása"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Globális MT-32 beállítások felülbírálása"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Mappák"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Mappák"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Játék Mappa:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Játék Mappa:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Extra Mappa:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Mappa kiválasztás a játékok kiegészítõ fájljaihoz"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Extra Mappa:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Mentés Mappa:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Játékmentések helyének meghatározása"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Mentés Mappa:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Nincs"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Alapértelmezett"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "SoundFont kiválasztás"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Játékok helyének kiválasztása"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Válassz mappát a játék kiegészítõkhöz"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Válaszz játékmentéseknek mappát"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Ez a játékazonosító ID már foglalt, Válassz egy másikat."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "Kilépés"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "ScummVM bezárása"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "Névjegy"
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "ScummVM névjegy"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pciók..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Globális ScummVM opciók cseréje"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "Indítás"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "A választott játék indítása"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~B~etölt..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Kimentett játékállás betöltése"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "Játék hozzáadás"
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Tratsd lenyomva a Shift-et a Masszív módhoz"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "Játékopciók"
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Játék beállítások megváltoztatása"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "Játék törlése"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Törli a játék nevét a listáról. A játékfájlok megmaradnak"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "Játék hozzáadás"
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "Játékopciók"
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "Játék törlése"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Keresés a játéklistában"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Keresés:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Játék betöltése:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Betöltés"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -610,40 +612,40 @@ msgstr ""
"Biztos hogy futtatod a Masszív játékdetektort? Ez potenciálisan sok játékot "
"hozzáad a listához."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM nem tudja megnyitni a választott mappát!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "A ScummVM nem talált egy játékot sem a választott mappában!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Válassztott játék:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Biztosan törölni akarod ezt a játékkonfigurációt?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Akarod hogy betöltésem a játékállást?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Ez a játék nem támogatja a játékállás betöltést az indítóból."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM nem talált olyan játékmotort ami a választott játékot támogatja!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Masszív mód..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Felvétel..."
@@ -686,197 +688,193 @@ msgstr "Átvált játékra"
msgid "Fast replay"
msgstr "Gyors visszajátszás"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Soha"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "5 percenként"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "10 percenként"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "15 percenként"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "30 percenként"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Nincs"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Néhány grafikus opció változtatása sikertelen:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "a videómód nem változott."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "a teljesképernyõs beállítás nem változott"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "a képméretarány beállítások nem változtak"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafikus mód:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Kirajzolás mód:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Néhány játék támogatja a speciális árnyalási módokat"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Teljesképernyõs mód:"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Képméretarány korrekció"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Helyes oldalarány a 320x200 játékokhoz"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Elsõdleges eszköz:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Zene eszköz:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Elsõdleges hangeszköz vagy hang emulátor beállítások"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Hangeszköz vagy hangkártya emulátor beállítások"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Elsõdleges eszk.:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Zene eszköz:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emulátor:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib meghajtót sok játék használja zenéhez"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Kimeneti ráta:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
msgstr ""
"Nagyobb értékek jobb hangminõséget adnak, de nem minden hangkártya támogatja"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM Eszköz:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Alapértelmezett hangeszköz General MIDI kimenethez"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Ne használj General MIDI zenét"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Elsõ elérhetõ eszköz használata"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"Néhány hangkárya, FluidSynth és Timidyti támogatja a SoundFont betöltését"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Vegyes AdLib/MIDI mód"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "MIDI és AdLib hanggenerátorok használata"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI erõsítés:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth Beállítása"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 Eszköz:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr "Roland MT-32/LAPC1/CM32l/CM64 alapértelmezett hangeszközök beállítása"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 Hardver (GM emuláció tiltva)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -884,16 +882,16 @@ msgstr ""
"Jelöld be, ha hardveres Roland-Kompatibilis hangeszköz van csatlakoztatva a "
"gépedhez és használni akarod"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 Hardver (GM emuláció nincs)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS eszköz (MT-32 mapping engedélyezés)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -901,169 +899,185 @@ msgstr ""
"Ellenõrzés ha engedélyezni akarod az emulált MT-32 Folt leképezést a Roland "
"GS eszközön"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Ne használj Roland MT-32 zenét"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Szöveg és beszéd:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Csak beszéd"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Csak felirat"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Mind"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Felirat sebesség:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Felirat és beszéd:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Besz"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Text"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Mind"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Hang és feliratok megjelenítése"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Felirat sebesség:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Zene hangerõ:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Zene hangerõ:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Összes némítása"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "SFX hangerõ:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Speciális hangeffektusok hangereje"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "SFX hangerõ:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Beszéd hangerõ:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Beszéd hangerõ:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth Beállítása"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Téma Mappa:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Téma Mappa:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Minden jéték és ScummVM kiegészítõ fájljainak mappája:"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Plugin Mappa:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Plugin Mappa:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Vegyes"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Téma:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI Renderelõ:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Automentés:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Automentés:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Billentyûk"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "GUI nyelve:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "A ScummVM GUI nyelve"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "Frissítés ellenõrzés:"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "Milyen gyakran ellenõrizze a ScummVM frissítéseket"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "Ellenõrzés most"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Indítsd újra a ScummVM-et a változások érvényesítéséhez."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "A kiválasztott mappába nem lehet írni, válassz egy másikat"
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "GUI téma mappa kiválasztása"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Mappa választás az extra fájloknak"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Plugin mappa kiválasztása"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1080,65 +1094,65 @@ msgstr "# következõ"
msgid "add"
msgstr "hozzáad"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Karakter törlés"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Elõzõ"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Szám"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Játékmenet felvétel vagy lejátszás"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Töröl"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Felvétel"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Visszajátszás"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Javít"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Szerzõ:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Megjegyzés:"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Biztos hogy törölni akarod ezt a felvételt?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Ismeretlen Szerzõ"
@@ -1202,7 +1216,7 @@ msgstr "Új játékmentés készítése"
msgid "Name: "
msgstr "Név:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Adj meg egy leírást a %d slothoz:"
@@ -1211,64 +1225,88 @@ msgstr "Adj meg egy leírást a %d slothoz:"
msgid "Select a Theme"
msgstr "Válassz témát"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX letiltva"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX letiltva"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standard leképezõ"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Átlagos"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Élsimításos leképezõ"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Élsimított"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM már támogatja az automatikus frissítéseket\n"
+"amelyhez internet hozzáférés szükséges.\n"
+"\n"
+"Szeretné, engedélyezni ezt a funkciót?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(Bármikor engedélyezheti a beállítások ablakban az Egyéb fülnél)"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Frissítések automatikus keresése"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Folyamatban"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Érték törlése"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "A motor nem támogatja a '%s' debug szintet"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menü"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Tovább"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Szünet"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Sor átlépése"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Hiba a játék futtatásakor:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Nem található olyan játékmotor ami a választott játékot támogatja"
@@ -1363,16 +1401,32 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Sárga"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "Naponta"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "Hetente"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "Havonta"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<Rossz érték>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "A '%s' játék ismeretlennek tûnik."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Kérlek jelezd a ScummVM csapatnak a következõ adatokat, együtt a játék"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "címével és megbízható adataival játékverzió/nyelv(ek)/stb.:"
@@ -1380,11 +1434,11 @@ msgstr "címével és megbízható adataival játékverzió/nyelv(ek)/stb.:"
msgid "~R~esume"
msgstr "Folytatás"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~B~etöltés"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "Mentés"
@@ -1409,15 +1463,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Visszatérés az indítóba"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Játék mentése:"
@@ -1426,15 +1480,16 @@ msgstr "Játék mentése:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Mentés"
@@ -1456,13 +1511,13 @@ msgstr ""
"(%s) játékmentés nem sikerült!. Olvassd el a README-t az alap "
"információkról, és hogy hogyan segíthetsz a késõbbiekben."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~M~égse"
@@ -1470,23 +1525,23 @@ msgstr "~M~égse"
msgid "~K~eys"
msgstr "Billentyük"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Szín formátum nincs alkalmazva"
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Videómód nincs átállítva: ' "
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Méretarány korrekció nem változott."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Teljesképernyõs beállítás nincs alkalmazva"
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1500,7 +1555,7 @@ msgstr ""
"adatfájljait a merevlemezedre.\n"
"Nézd meg a README fájlt a részletekért."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1514,7 +1569,7 @@ msgstr ""
"hogy a játék zenéje hallható legyen.\n"
"Nézd meg a README fájlt a részletekért."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1523,7 +1578,7 @@ msgstr ""
"(%s) játékállás betöltése nem sikerült!. Olvassd el a README-t az alap "
"információkról, és hogy hogyan segíthetsz a késõbbiekben."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1533,11 +1588,11 @@ msgstr ""
"ScummVM. Számíts rá hogy nem stabilan fut, és a mentések nem mûködnek a "
"jövõbeni ScummVM verziókkal."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Indítás így is"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib Emulátor"
@@ -1616,11 +1671,11 @@ msgstr "FM-Towns Hang"
msgid "PC-98 Audio"
msgstr "PC-98 Hang"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "MT-32 Emulátor inicializálása"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 Emulátor"
@@ -1652,7 +1707,7 @@ msgstr "Biztos hogy ki akarsz lépni ?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Kilépés"
@@ -1737,11 +1792,11 @@ msgstr "Auto-húz módban van"
msgid "Swipe three fingers to the right to toggle."
msgstr "Üsd három újjal hogy biztosan váltson."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (Nincs szûrés)"
@@ -1756,19 +1811,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normál (nincs átméretezés)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Méretarány korrekció engedélyezve"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Méretarány korrekció letiltva"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktív grafikus szûrõk:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Ablakos mód"
@@ -1801,7 +1856,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "Bezár"
@@ -2291,20 +2346,36 @@ msgstr ""
"Ne felejts billentyût társítani az 'Eszköztár rejtés' mûvelethez, hogy lásd "
"a teljes listát"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Frissítések keresése..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Szines mód"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Szines grafikát használ"
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "Pászta"
+
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Pászta megjelenítés"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Eredeti ment/tölt képernyõk használata"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Az eredeti mentés/betöltés képernyõ használata a ScummVM képek helyett"
@@ -2332,27 +2403,47 @@ msgstr ""
"Egérmód engélyezve. Lehetõvé teszi az egérrel mozgatást játékban és "
"játékmenükben."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "Hercules hires font használata"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr "Hercules hires font használata, ha a font fájl elérhetõ."
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "Szünet a parancsok beírásakor"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"Parancssor ablak megjelenítése és játék szüneteltetése (mint a SCI) valós "
+"idejü parancs helyett."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Játékmenet visszaállítása:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Visszaállítás"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2363,7 +2454,7 @@ msgstr ""
"\n"
"%s fájlból nem sikerült"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2374,7 +2465,7 @@ msgstr ""
"\n"
"%s fájlba nem sikerült"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2385,7 +2476,7 @@ msgstr ""
"\n"
"%s fájlba elkészült"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "'%s' átvezetõ fájl nem található"
@@ -2415,20 +2506,20 @@ msgstr ""
"Nyomj OK-t ha átalakítod most, vagy rákérdezek újra ha legközelebb elindítod "
"a játékot.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Fényes paletta mód használata"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Grafikus megjelenítésre használja a játék fényes palettáját"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Játékállás betöltése fájlból nem sikerült."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Játékállás mentése fájlba nem sikerült."
@@ -2445,7 +2536,7 @@ msgstr "Gyors filmsebesség"
msgid "Play movies at an increased speed"
msgstr "Filmek lejátszása nagyobb sebességgel"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Játék mentés nem sikerült"
@@ -2619,50 +2710,58 @@ msgstr ""
"utasítást.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "Myst bevezetõ film lejátszása"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr "A Myst bevezetõ filmet nem játszotta le az eredeti motor."
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ip Mód aktiválva"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~Á~tmenetek engedélyezve"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "Oldal~D~obás"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
-msgstr "~S~ Térkép"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
+msgstr "~M~ Térkép nézet"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
-msgstr "Fõ~M~enü"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
+msgstr "Fõ Menü ~u~"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "Vízeffektus engedélyezve"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Hall of Records storyboard átvezetõk átugrása"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Lehetõség, hogy a játékos átugorja a Hall of Records storyboard átvezetõket"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Hogyan készült videók átméretezése teljesképernyõre"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Hogyan készült videók átméretezése, hogy teljesképernyõt használjanak"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2671,23 +2770,23 @@ msgstr ""
"Játékállás nem menthetõ %i slotba\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Fájl betöltése"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Játék betöltés..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Fájl mentése"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Játék mentés..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2703,11 +2802,11 @@ msgstr ""
"Nyomj OK-t az átalakításhoz, vagy rákérdezzek ha legközelebb elindítod a "
"játékot.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM konvertálta az összes játékállásodat."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2763,36 +2862,44 @@ msgstr "Alternatív intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "Alternatív játékintro használata (csak CD verziónál)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "EGA színmoduláció átugrása (Színes háttereknél)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Színmoduláció átugrása EGA játékoknál, grafikák teljes színben láthatók"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Nagy felbontású grafika engedélyezése"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Nagy felbontású grafika/tartalom engedélyezése"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr "Feketevonalas videó engedélyezve"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr "Fekete vonalat rajzol a videó fölé, hogy növelje a kép élességét"
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Digitális hangeffektusok elõnyben"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Digitális hanghatások elõnyben a szintetizáltakkal szemben"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "IMF/Yamaha FB-01 használata MIDI kimentre"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2800,145 +2907,153 @@ msgstr ""
"IBM Music Feature kártya vagy Yamaha FB-01 FM szintetizátor modul használata "
"MIDI kimenetre"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "CD audió használata"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "CD audió használata a játékban lévõvel szemben, ha elérhetõ"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Windows kurzorok használata"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr "Windows kurzorok használata (kisebb és monokróm) a DOS-osok helyett "
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Ezüst kurzor használata"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr "Alternatív ezüst kurzorszett használata, a normál arany helyett"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "Tárgynév sor látható"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "Tárgyak neveinek megjelenítése a képernyõ alján"
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Helyezd be a %c lemezt és gombnyomás a folytatáshoz."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "%s, (%c%d) nem található. Nyomj egy billentyût."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Hiba a %c, (%c%d) lemez olvasásakor. Nyomj egy billentyût."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Játék szünetel. SPACE a folytatáshoz."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Biztos hogy újra akarod indítani? (I/N)I"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Biztos hogy ki akarsz lépni? (I/N)I"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Játék"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Helyezd be a játékmentés lemezt"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Meg kell adnod egy nevet"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "A játék NINCS mentve (Megtelt a lemez?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "A játék NINCS betöltve"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "'%s' Mentése"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "'%s' Betöltése"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "JátékMENTÉS neve"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Válassz egy játékot Betöltésre"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Játék címe)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~E~lõzõ"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "Következõ"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Csak beszéd"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Beszéd és felirat"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Csak felirat"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Beszéd & Felir"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Válassz hozzáértés szintet."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Segítségért nézd meg a Loom(TM) kézikönyvedet."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Gyakorlás"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Szakértõ"
@@ -3475,23 +3590,23 @@ msgstr "Jobbra repülés"
msgid "Fly to lower right"
msgstr "Jobbra le repülés"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Finomgörgetés be"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Finomgörgetés ki"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Zene hangereje:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Felirat sebesség:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3500,7 +3615,7 @@ msgstr ""
"Native MIDI támogatáshoz kell a Roland Upgrade a LucasArts-tól,\n"
"a %s hiányzik. AdLib-ot használok helyette."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3682,12 +3797,22 @@ msgstr "Tárgycimke látható"
msgid "Show labels for objects on mouse hover"
msgstr "Tárgycimke látható ha az egér felette van"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "Angol beszéd használata"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+"Angol beszéd használata a Német helyett minden nyelven, a Németen kívül"
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Hiányzik a 'teenagent.dat' fájl. Szerezd be a ScummVM website-ról"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3785,9 +3910,6 @@ msgstr "MPEG videót használ DVD verziónál, a kisebb felbontású AVI helyett"
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktív filter mód: Közelítõ"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Roland GS Mód engedélyezve"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Játék hozzáadás"
diff --git a/po/it_IT.po b/po/it_IT.po
index 880c0ca7df..1313610398 100644
--- a/po/it_IT.po
+++ b/po/it_IT.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2014-07-03 17:59-0600\n"
"Last-Translator: Matteo 'Maff' Angelino <matteo.maff at gmail dot com>\n"
"Language-Team: Italian\n"
@@ -52,15 +52,16 @@ msgstr "Su"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Annulla"
@@ -100,7 +101,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Sei sicuro di voler eliminare questo salvataggio?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -110,7 +111,7 @@ msgid "Yes"
msgstr "Sì"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -171,7 +172,7 @@ msgstr "Seno"
msgid "Triangle"
msgstr "Triangolo"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Varie"
@@ -204,14 +205,14 @@ msgid "Reset all FluidSynth settings to their default values."
msgstr ""
"Ripristina tutte le impostazioni di FluidSynth al loro valore predefinito."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -241,15 +242,15 @@ msgstr "Chiudi"
msgid "Mouse click"
msgstr "Clic del mouse"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostra tastiera"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Riprogramma tasti"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Attiva / disattiva schermo intero"
@@ -324,8 +325,8 @@ msgid ""
msgstr ""
"Lingua del gioco. Un gioco inglese non potrà risultare tradotto in italiano"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<predefinito>"
@@ -347,11 +348,11 @@ msgstr "Piattaf.:"
msgid "Engine"
msgstr "Motore"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafica"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "Grafica"
@@ -364,7 +365,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Ignora le impostazioni grafiche globali"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Audio"
@@ -377,11 +378,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Ignora le impostazioni audio globali"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volume"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volume"
@@ -395,216 +396,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Ignora le impostazioni globali di volume"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Ignora le impostazioni MIDI globali"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Ignora le impostazioni MIDI globali"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Ignora le impostazioni MT-32 globali"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Ignora le impostazioni MT-32 globali"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Percorsi"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Perc."
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Percorso gioco:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Perc. gioco:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Percorso extra:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Specifica il percorso di ulteriori dati usati dal gioco"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Perc. extra:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Salvataggi:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Specifica dove archiviare i salvataggi"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Salvataggi:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Nessuno"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Predefinito"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Seleziona SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Seleziona la cartella contenente i file di gioco"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Seleziona la cartella di gioco aggiuntiva"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Seleziona la cartella dei salvataggi"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Questo ID di gioco è già in uso. Si prega di sceglierne un'altro."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "C~h~iudi"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Esci da ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "~I~nfo..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Informazioni su ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pzioni..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Modifica le opzioni globali di ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~G~ioca"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Esegue il gioco selezionato"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~C~arica..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Carica un salvataggio del gioco selezionato"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~A~ggiungi gioco..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Tieni premuto Shift per l'aggiunta in massa"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~M~odifica gioco..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Modifica le opzioni di gioco"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~R~imuovi gioco"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Rimuove il gioco dalla lista. I file del gioco rimarranno intatti"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~A~gg. gioco..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~M~odif. gioco..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~R~im. gioco"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Cerca nella lista dei giochi"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Cerca:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Carica gioco:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Carica"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -612,43 +614,43 @@ msgstr ""
"Vuoi davvero eseguire il rilevatore di giochi in massa? Potrebbe aggiungere "
"un numero enorme di giochi."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM non ha potuto aprire la cartella specificata!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM non ha potuto trovare nessun gioco nella cartella specificata!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Scegli il gioco:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Sei sicuro di voler rimuovere questa configurazione di gioco?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vuoi caricare il salvataggio?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr ""
"Questo gioco non supporta il caricamento di salvataggi dalla schermata di "
"avvio."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM non ha potuto trovare un motore in grado di eseguire il gioco "
"selezionato!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Agg. in massa..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -693,134 +695,134 @@ msgstr "Sposta"
msgid "Fast replay"
msgstr "Modalità veloce"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Mai"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "ogni 5 minuti"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "ogni 10 minuti"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "ogni 15 minuti"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "ogni 30 minuti"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Nessuno"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Impossibile applicare alcuni dei cambiamenti nelle opzioni grafiche."
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "impossibile modificare la modalità video."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "impossibile modificare l'impostazione schermo intero"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "impossibile modificare l'impostazione proporzioni"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Modalità:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Resa grafica:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Modalità di resa grafica speciali supportate da alcuni giochi"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Modalità a schermo intero"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Correzione proporzioni"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Corregge le proporzioni dei giochi 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Disp. preferito:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Dispositivo audio:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
"Specifica il dispositivo audio o l'emulatore della scheda audio preferiti"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr ""
"Specifica il dispositivo di output audio o l'emulatore della scheda audio"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Disp. preferito:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Disposit. audio:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Emulatore AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib è utilizzato per la musica in molti giochi"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Frequenza:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -828,66 +830,62 @@ msgstr ""
"Valori più alti restituiscono un suono di maggior qualità, ma potrebbero non "
"essere supportati dalla tua scheda audio"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Dispositivo GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Specifica il dispositivo audio predefinito per l'output General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Non utilizzare la musica General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Utilizza il primo dispositivo disponibile"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "SoundFont è supportato da alcune schede audio, FluidSynth e Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Modalità mista AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Utilizza generazione di suono sia MIDI che AdLib"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Guadagno MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Impostazioni FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Disposit. MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Specifica il dispositivo audio predefinito per l'output Roland MT-32/LAPC1/"
"CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 effettivo (disattiva emulazione GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -895,16 +893,16 @@ msgstr ""
"Seleziona se vuoi usare il dispositivo hardware audio compatibile con Roland "
"che è connesso al tuo computer"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 effettivo (disat.emul.GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Dispositivo Roland GS (attiva mappature MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -912,169 +910,185 @@ msgstr ""
"Seleziona se vuoi attivare le mappature per emulare un MT-32 su un "
"dispositivo Roland GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Non utilizzare la musica Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Testo e voci:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Voci"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Sottotitoli"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Entrambi"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Velocità testo:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Testo e voci:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Voci"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Sub"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Entr."
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Mostra i sottotitoli e attiva le voci"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Velocità testo:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Volume musica:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Volume musica:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Disattiva audio"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Volume effetti:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volume degli effetti sonori"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Volume effetti:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Volume voci:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Volume voci:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Impostazioni FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Percorso tema:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Perc. tema:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Specifica il percorso di ulteriori dati usati dai giochi o da ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Percorso plugin:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Perc. plugin:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Varie"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Renderer GUI:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autosalva:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autosalva:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Tasti"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Lingua GUI:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Lingua dell'interfaccia grafica di ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Devi riavviare ScummVM affinché le modifiche abbiano effetto."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "La cartella scelta è in sola lettura. Si prega di sceglierne un'altra."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Seleziona la cartella dei temi dell'interfaccia"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Seleziona la cartella dei file aggiuntivi"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Seleziona la cartella dei plugin"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1091,68 +1105,68 @@ msgstr ""
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Elimina"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr ""
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Elimina"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
#, fuzzy
msgid "Playback"
msgstr "Gioca"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr ""
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr ""
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr ""
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
#, fuzzy
msgid "Do you really want to delete this record?"
msgstr "Sei sicuro di voler eliminare questo salvataggio?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
#, fuzzy
msgid "Unknown Author"
msgstr "Errore sconosciuto"
@@ -1217,7 +1231,7 @@ msgstr "Crea un nuovo salvataggio"
msgid "Name: "
msgstr "Nome: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Inserisci una descrizione per la posizione %d:"
@@ -1226,64 +1240,85 @@ msgstr "Inserisci una descrizione per la posizione %d:"
msgid "Select a Theme"
msgstr "Seleziona un tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Grafica disattivata"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Grafica disattivata"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Renderer standard"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Medio"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Renderer con antialiasing"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Con antialiasing"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Cerca aggiornamenti..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Cancella"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Il motore non supporta il livello di debug '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Salta"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pausa"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Salta battuta"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Errore nell'esecuzione del gioco:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr ""
"Impossibile trovare un motore in grado di eseguire il gioco selezionato"
@@ -1379,16 +1414,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules ambra"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Cancella"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Il gioco in '%s' sembra essere sconosciuto."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Per favore, riporta i seguenti dati al team di ScummVM con il nome"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "del gioco che hai provato ad aggiungere e la sua versione/lingua/ecc.:"
@@ -1396,11 +1448,11 @@ msgstr "del gioco che hai provato ad aggiungere e la sua versione/lingua/ecc.:"
msgid "~R~esume"
msgstr "~R~ipristina"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~C~arica"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~S~alva"
@@ -1425,15 +1477,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~ai a elenco giochi"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Salva gioco:"
@@ -1442,15 +1494,16 @@ msgstr "Salva gioco:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Salva"
@@ -1474,13 +1527,13 @@ msgstr ""
"informazioni di base e per le istruzioni su come ottenere ulteriore "
"assistenza."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~nnulla"
@@ -1488,23 +1541,23 @@ msgstr "~A~nnulla"
msgid "~K~eys"
msgstr "~T~asti"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Impossibile inizializzare il formato colore."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Impossibile cambiare la modalità video: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Impossibile applicare l'impostazione proporzioni"
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Impossibile applicare l'impostazione schermo intero."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1518,7 +1571,7 @@ msgstr ""
"sull'hard disk.\n"
"Vedi il file README per i dettagli."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1532,7 +1585,7 @@ msgstr ""
"la musica del gioco.\n"
"Vedi il file README per i dettagli."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1542,7 +1595,7 @@ msgstr ""
"per le informazioni di base e per le istruzioni su come ottenere ulteriore "
"assistenza."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1552,11 +1605,11 @@ msgstr ""
"ScummVM. È quindi possibile che sia instabile, e i salvataggi potrebbero non "
"funzionare con future versioni di ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Avvia comunque"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Emulatore AdLib"
@@ -1639,11 +1692,11 @@ msgstr "Emulatore FM Towns"
msgid "PC-98 Audio"
msgstr "Audio"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Avvio in corso dell'emulatore MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Emulatore MT-32"
@@ -1675,7 +1728,7 @@ msgstr "Sei sicuro di voler uscire?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Esci"
@@ -1761,11 +1814,11 @@ msgstr ""
msgid "Swipe three fingers to the right to toggle."
msgstr ""
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (senza filtri)"
@@ -1780,19 +1833,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normale (no ridim.)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Correzione proporzioni attivata"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Correzione proporzioni disattivata"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Filtro grafico attivo:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Modalità finestra"
@@ -1825,7 +1878,7 @@ msgid "Windows MIDI"
msgstr "MIDI Windows"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~C~hiudi"
@@ -2318,20 +2371,38 @@ msgstr ""
"Non dimenticare di mappare un tasto per l'azione \"Nascondi barra degli "
"strumenti\" per vedere l'intero inventario"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Cerca aggiornamenti..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Modalità clic"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Mostra etichette oggetti"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Usa schermate di salvataggio originali"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2359,27 +2430,46 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules verde"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Ripristina gioco:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Ripristina"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2390,7 +2480,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2401,7 +2491,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2412,7 +2502,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "File della scena di intermezzo '%s' non trovato!"
@@ -2444,20 +2534,20 @@ msgstr ""
"Premi OK per convertirli adesso, altrimenti ti verrà richiesto al prossimo "
"avvio del gioco.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Usa modalità colori brillanti"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Visualizza la grafica con i colori brillanti del gioco"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Impossibile caricare il gioco dal file."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Impossibile salvare il gioco nel file."
@@ -2474,7 +2564,7 @@ msgstr "Alta velocità filmati"
msgid "Play movies at an increased speed"
msgstr "Aumenta la velocità di riproduzione dei filmati"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Impossibile salvare il gioco"
@@ -2635,49 +2725,59 @@ msgid ""
"\n"
msgstr ""
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "Modalità ~Z~ip attivata"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~T~ransizioni attive"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~L~ascia pagina"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~M~ostra mappa"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~M~enu principale"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~E~ffetto acqua attivo"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Salta le scene della Hall of Records"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "Permette al giocatore di saltare le scene della Hall of Records"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Ridimensiona a tutto schermo i video dietro le quinte"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Ridimensiona i video dietro le quinte, per adattarli allo schermo"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2686,25 +2786,25 @@ msgstr ""
"Impossibile salvare nella posizione %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
#, fuzzy
msgid "Load file"
msgstr "Carica gioco:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Caricamento..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
#, fuzzy
msgid "Save file"
msgstr "Salvataggio fallito!"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Salvataggio..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2721,11 +2821,11 @@ msgstr ""
"Premi OK per convertirli adesso, altrimenti ti verrà richiesto la prossima "
"volta.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM ha convertito con successo tutti i tuoi salvataggi."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2781,37 +2881,46 @@ msgstr "Intro alternativa"
msgid "Use an alternative game intro (CD version only)"
msgstr "Usa un'intro del gioco alternativa (solo versione CD)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
#, fuzzy
msgid "Enable high resolution graphics"
msgstr "Attiva le barre di Hit Point"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
#, fuzzy
msgid "Enable high resolution graphics/content"
msgstr "Attiva le barre di Hit Point"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Attiva la modalità Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Scegli effetti sonori digitali"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Scegli gli effetti sonori digitali al posto di quelli sintetizzati"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Usa IMF/Yamaha FB-01 per output MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2819,150 +2928,159 @@ msgstr ""
"Usa una scheda IBM Music Feature o un modulo synth Yamaha FB-01 FM per "
"l'output MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Usa audio da CD"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"Usa l'audio da CD al posto di quello incorporato nel gioco, se disponibile"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Usa cursori di Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Usa i cursori di Windows (più piccoli e monocromatici) al posto di quelli DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Usa cursori d'argento"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Usa il set alternativo di cursori d'argento al posto di quelli normali d'oro"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Mostra etichette oggetti"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Inserisci il disco %c e premi un pulsante per continuare."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Impossibile trovare %s, (%c%d) Premere un pulsante."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Errore nella lettura del disco %c, (%c%d) Premere un pulsante."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Gioco in pausa. Premere SPAZIO per continuare."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
#, fuzzy
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Sei sicuro di voler riavviare? (S/N)S"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
#, fuzzy
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Sei sicuro di voler uscire? (S/N)S"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Gioca"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Inserire il disco dei salvataggi"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Devi inserire un nome"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Il gioco NON è stato salvato (disco pieno?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Il gioco NON è stato caricato"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Salvataggio di '%s' in corso"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Caricamento di '%s' in corso"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Dai un nome al SALVATAGGIO"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Seleziona un gioco da caricare"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "titolo gioco)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~P~recedenti"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~S~uccessivi"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Solo voci"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voci e testo"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Solo testo"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voci e testo"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selezionate un livello di difficoltà."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Consultate il manuale delle istruzioni."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Base"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3500,26 +3618,26 @@ msgstr "Vola a destra"
msgid "Fly to lower right"
msgstr "Vola in basso a destra"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
#, fuzzy
msgid "Snap scroll on"
msgstr "Scorrimento morbido"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
#, fuzzy
msgid "Music volume: "
msgstr "Volume musica:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
#, fuzzy
msgid "Subtitle speed: "
msgstr "Velocità testo:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3528,7 +3646,7 @@ msgstr ""
"Il supporto nativo MIDI richiede il Roland Upgrade della LucasArts,\n"
"ma %s non è presente. Verrà usato AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
#, fuzzy
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
@@ -3708,12 +3826,21 @@ msgstr "Mostra etichette oggetti"
msgid "Show labels for objects on mouse hover"
msgstr "Mostra etichette per gli oggetti al passaggio del mouse"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Il file 'teenagent.dat' non è presente. Scaricarlo dal sito di ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3820,9 +3947,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Modalità filtro attiva: Più vicino"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Attiva la modalità Roland GS"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Agg. gioco..."
diff --git a/po/nb_NO.po b/po/nb_NO.po
index 8f105c6d55..f683f85535 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-25 23:42+0100\n"
"Last-Translator: Einar Johan Trøan Sømåen <einarjohants@gmail.com>\n"
"Language-Team: somaen <einarjohants@gmail.com>\n"
@@ -55,15 +55,16 @@ msgstr "Oppover"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Avbryt"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Vil du virkelig overskrive denne filen?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "Ja"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Trekant"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Diverse"
@@ -205,14 +206,14 @@ msgstr "Nullstill"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Nullstill alle FluidSynth-instillinger til standardverdier"
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -241,15 +242,15 @@ msgstr "Lukk"
msgid "Mouse click"
msgstr "Musklikk"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Vis tastatur"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Omkoble taster"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Veksle fullskjerm"
@@ -325,8 +326,8 @@ msgstr ""
"Spillets språk. Dette vil ikke gjøre din spanske spillversjon om til engelsk "
"versjon"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<standard>"
@@ -348,11 +349,11 @@ msgstr "Plattform:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafikk"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -365,7 +366,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Overstyr globale grafikkinstillinger"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Lyd"
@@ -378,11 +379,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Overstyr globale lydinstillinger"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volum"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volum"
@@ -396,216 +397,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Overstyr globale voluminstillinger"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Overstyr globale MIDI-instillinger"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Overstyr globale MIDI-instillinger"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Overstyr globale MT-32-instillinger"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Overstyr globale MT-32-instillinger"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Sti"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Sti"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Spillsti:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Spillsti:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Ekstrasti:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Bestemmer sti til ytterligere data brukt av spillet"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Ekstrasti:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Lagringssti:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Bestemmer sti til lagrede spill"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Lagringssti:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ingen"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Standard"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Velg SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Velg mappe med spilldata"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Velg mappe med ytterligere data"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Velg mappe for lagrede spill"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Denne spill-IDen er allerede i bruk. Vennligst velg en annen."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~A~vslutt"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Avslutt ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "~O~m..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Om ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~V~alg..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Endre globale ScummVM-innstillinger"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tart"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Start valgt spill"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~Å~pne..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Åpne lagret spill for det valgte spillet"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~L~egg til spill..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Hold Shift for å legge til flere"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~R~ediger spill..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Endre spillinstillinger"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~F~jern spill"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Fjern spill fra listen. Spilldataene forblir intakte"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~L~egg til spill..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~R~ediger spill..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~F~jern spill"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Søk i spilliste"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Søk:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Åpne spill:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Åpne"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -613,40 +615,40 @@ msgstr ""
"Vil du virkelig kjøre flerspill-finneren? Dette kan potensielt legge til et "
"stort antall spill."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunne ikke åpne den valgte mappen!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM kunne ikke finne noe spill i den valgte mappen!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Velg spill:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Vil du virkelig fjerne denne spillkonfigurasjonen?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vil du laste et lagret spill?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Dette spillet støtter ikke lasting av spill fra oppstarteren."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM kunne ikke finne noen motor som kunne kjøre det valgte spillet!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Legg til flere..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -691,132 +693,132 @@ msgstr "Bytt til Spill"
msgid "Fast replay"
msgstr "Rask replay"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Aldri"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "hvert 5. min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "hvert 10. min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "hvert 15. min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "hvert 30. min"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ingen"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Klarte ikke å aktivere enkelte av endringene i grafikkinstillinger:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "videomodusen kunne ikke endres."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "fullskjermsinnstillingen kunne ikke endres"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "aspektrate-innstillingen kunne ikke endres"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafikkmodus:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Tegnemodus:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Spesiel dithering-modus støttet av enkelte spill"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Fullskjermsmodus"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Aspekt-rate korrigering"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Korriger aspekt-rate for 320x200-spill"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Foretrukket enhet:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musikkenhet:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Velger foretrukket lydenhet eller lydkort-emulator"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Velger ut-lydenhet eller lydkortemulator"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Foretrukket enh.:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musikkenhet:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib-emulator:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib brukes til musikk i mange spill"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Utrate:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -824,64 +826,60 @@ msgstr ""
"Høyere verdier gir bedre lydkvalitet, men støttes kanskje ikke av ditt "
"lydkort "
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM-enhet:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Velger standard lydenhet for General MIDI-utdata"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Ikke bruk General MIDI-musikk"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Bruk første tilgjengelige enhet"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "SoundFont støttes ikke av enkelte lydkort, FluidSynth og Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Mikset AdLib/MIDI-modus"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Bruk både MIDI- og AdLib- lydgenerering"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI gain:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth-instillinger"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 Enhet:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr "Velger standard lydenhet for Roland MT-32/LAPC1/CM32I/CM64-avspilling"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Ekte Roland MT-32 (deaktiver GM-emulering)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -889,16 +887,16 @@ msgstr ""
"Velg hvis du har et ekte Roland-kompatible lydkort tilkoblet maskinen, og "
"vil bruke dette."
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Ekte Roland MT-32 (deaktiver GM-emulering)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS Modus (aktiver MT32-mapping)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -906,169 +904,185 @@ msgstr ""
"Aktiver hvis du vil slå på patch mappinger for å emulere en MT-32 eller "
"Roland GS enhet"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Ikke bruk Roland MT-32-musikk"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Tekst og Tale:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Tale"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Undertekster"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Begge"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Teksthastighet:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Tekst og Tale:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Tale"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Tekst"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Begge"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Vis undertekster, og spill av tale"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Underteksthastighet:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musikkvolum:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musikkvolum:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Demp alle"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Lydeffektvolum:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volum for spesielle lydeffekter"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Lydeffektvolum:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Talevolum:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Talevolum:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth-instillinger"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Temasti:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Temasti:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Velger sti for ytterligere data brukt av alle spill eller ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Pluginsti:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Pluginsti:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Div"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI-tegner:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autolagre:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autolagre:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Taster"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "GUI-språk:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Språk i ScummVM-GUIet"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Du må starte ScummVM på nytt for at endringene skal tre i kraft. "
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Den valgte mappen kan ikke skrives til. Vennligst velg en annen."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Velg mappe for GUI-temaer"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Velg mappe for ytterligere filer"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Velg mappe for plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1085,65 +1099,65 @@ msgstr "# neste"
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr ""
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Tall"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Slett"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr ""
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Rediger"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Forfatter: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notater: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr ""
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Ukjent Forfatter"
@@ -1207,7 +1221,7 @@ msgstr "Opprett ett nytt lagret spill."
msgid "Name: "
msgstr "Navn:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Gi en beskrivelse for posisjon %d:"
@@ -1216,64 +1230,85 @@ msgstr "Gi en beskrivelse for posisjon %d:"
msgid "Select a Theme"
msgstr "Velg et tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Deaktivert GFX"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Deaktivert GFX"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standard tegner"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Kantutjevnet tegner"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Kantutjevnet"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Sjekk for oppdateringer..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Tøm verdi"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Motoren støtter ikke debug-nivå '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Meny"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Hopp over"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pause"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Hopp over linje"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Problem ved kjøring av spill:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Kunne ikke finne noen motor som kunne kjøre det valgte spillet"
@@ -1368,17 +1403,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Oransje"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Tøm verdi"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Spillet i '%s' ser ut til å være ukjent."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Vennligst rapporter de følgende dataene til ScummVM-teamet sammen med navnet"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "på spillet du forsøkte å legge til, og dets versjon/språk/etc.:"
@@ -1386,11 +1438,11 @@ msgstr "på spillet du forsøkte å legge til, og dets versjon/språk/etc.:"
msgid "~R~esume"
msgstr "~F~ortsett"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~Å~pne"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~L~agre"
@@ -1415,15 +1467,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~T~ilbake til oppstarter"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Lagret spill:"
@@ -1432,15 +1484,16 @@ msgstr "Lagret spill:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Lagre"
@@ -1463,13 +1516,13 @@ msgstr ""
"Lagring av spilltilstand feilet (%s)! Vennligst konsulter README-filen for "
"grunnleggende informasjon og instruksjon om hvordan du får ytterligere hjelp."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~vbryt"
@@ -1477,23 +1530,23 @@ msgstr "~A~vbryt"
msgid "~K~eys"
msgstr "~T~aster"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kunne ikke initalisere fargeformat."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunne ikke veksle til videomodus: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikke aktivere aspektrate-innstilling."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikke aktivere fullskjermsinnstilling."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1507,7 +1560,7 @@ msgstr ""
"datafilene til harddisken din istedet.\n"
"Se README-filen for detaljer."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1521,7 +1574,7 @@ msgstr ""
"kunne høre på spillets musikk.\n"
"Se README-filen for detaljer."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1530,7 +1583,7 @@ msgstr ""
"Klarte ikke laste spill (%s)! Vennligst se i README-fila for grunnleggende "
"informasjon og instruksjoner om hvordan du kan få mer hjelp."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1540,11 +1593,11 @@ msgstr ""
"Derfor er det sannsynlig at det vil være ustabilt, og det er ikke sikkert at "
"lagrede spill vil fortsette å fungere i fremtidige versjoner av ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Start allikevel"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib Emulator"
@@ -1625,11 +1678,11 @@ msgstr "FM Towns Lyd"
msgid "PC-98 Audio"
msgstr "PC-98 Lyd"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Initialiserer MT-32-Emulator"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 Emulator"
@@ -1661,7 +1714,7 @@ msgstr "Vil du virkelig avslutte?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Avslutt"
@@ -1746,11 +1799,11 @@ msgstr "Auto-dramodus er nå"
msgid "Swipe three fingers to the right to toggle."
msgstr "Sveip tre fingre til høyre for å veksle"
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (Ingen filtrering)"
@@ -1765,19 +1818,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (ingen skalering)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Aspekt-rate korrigering aktivert"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Aspekt-rate korrigering deaktivert"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktivt grafikkfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Vindusmodus"
@@ -1810,7 +1863,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~L~ukk"
@@ -2303,20 +2356,38 @@ msgstr ""
"Ikke glem å koble en tast til handlingen 'Skjul verktøylinje' for å se hele "
"inventaret"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Sjekk for oppdateringer..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Fargeblindmodus"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Vis objektmerkelapper"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Bruk originale lagre/laste-skjermer"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Bruk de originale lagre/laste-skjermene, istedenfor ScummVM-variantene"
@@ -2343,27 +2414,46 @@ msgid ""
msgstr ""
"Aktiver musstøtte. Tillater å bruke mus for bevegelse og i spillmenyer."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules Grønn"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Gjennopprett spill:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Gjenopprett"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2374,7 +2464,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2385,7 +2475,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2396,7 +2486,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Fant ikke cutscenefil '%s'!"
@@ -2427,20 +2517,20 @@ msgstr ""
"Trykk OK for å konvertere dem nå, ellers vil du bli spurt igjen neste gang "
"du starter spillet. \n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Bruk lys palettmodus"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Vis grafikk med spillets lyse palett"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Klarte ikke åpne spilltilstand fra fil."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Klarte ikke lagre spilltilstand fra fil."
@@ -2457,7 +2547,7 @@ msgstr "Rask filmhastighet"
msgid "Play movies at an increased speed"
msgstr "Spill filmer med økt hastighet"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Klarte ikke å lagre spill."
@@ -2630,49 +2720,59 @@ msgstr ""
"ScummVM debugkonsollen og bruke kommandoen «import_savefile»\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ipmodus aktivert"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~O~verganger aktivert"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~D~ropp Side"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "Vi~s~ Kart"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "Hoved~m~eny"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~V~anneffekt aktivert"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Hopp over Hall of Records storyboard scenene."
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "Tillater spilleren å hoppe forbi Hall of Records storyboard scener. "
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Skaler «making of»-videoer til fullskjerm"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Skaler «making of»-videoene, slik at de bruker hele skjermen."
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2681,23 +2781,23 @@ msgstr ""
"Kan ikke lagre spilltilstand i posisjon %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Last fil"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Laster spill..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Lagre fil"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Lagrer spill..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2714,11 +2814,11 @@ msgstr ""
"Trykk OK for å konvertere dem nå, ellers vil du bli spurt igjen neste gang "
"du starter spillet.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM konverterte alle de lagrede spillene dine uten problemer."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2774,35 +2874,44 @@ msgstr "Alternativ intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "Bruk en alternativ intro (Kun for CD-versjon)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Hopp over EGA dithering (fullfarge bakgrunner)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Aktiver høyoppløselig grafikk"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Aktiver høyoppløselig grafikk/innhold"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Aktiver Roland GS-modus"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Foretrekk digitale lydeffekter"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Foretrekk digitale lydeffekter fremfor syntetiske"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Bruk IMF/Yamaha-FB-01 for MIDI-output"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2810,146 +2919,155 @@ msgstr ""
"Bruk et IBM Music Feature-kort eller en Yamaha FB-01 FM-synthmodul til MIDI "
"output"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Bruk CD-lyd"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Bruk CD-lyd istedenfor spillets lyd, hvis tilgjengelig"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Bruk Windows-muspekere"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr "Bruk Windows-muspekerene (mindre, og monokrome) isteden"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Bruk sølvmuspekere"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Bruk det alternative settet med sølvmuspekere, istedenfor de normale gylne."
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Vis objektmerkelapper"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Sett inn disk %c, og trykk Tast for å fortsette."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Fant ikke %s, (%c%d) Trykk Knapp."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Feil ved lesing av disk %c, (%c%d) Trykk Knapp."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Spill pauset. Trykk på MELLOMROMstasten for å fortsette."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Er du sikker på at du vil starte på nytt? (J/N)J"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Er du sikker på at du vil avslutte? (J/N)J"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Spill"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Sett inn disk for lagrede spill"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Du må skrive inn et navn"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Spillet ble IKKE lagret (full disk?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Spillet ble IKKE lastet"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Lagrer '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Laster '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Gi det LAGREDE spillet ditt et navn"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Velg et spill for LASTING"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Spilltittel)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~F~orrige"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~N~este"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Kun tale"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tale og undertekster"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Kun undertekster"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tekst & Tale"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Velg ferdighetsnivå"
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Referer til Loom(TM)-håndboka di for hjelp."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Trening"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3486,23 +3604,23 @@ msgstr "Fly til høyre"
msgid "Fly to lower right"
msgstr "Fly til nedre høyre"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr ""
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Musikkvolum: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Teksthastighet: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3511,7 +3629,7 @@ msgstr ""
"Ekte MIDI-støtte krever «Roland Upgrade» fra LucasArts,\n"
"men %s mangler. Bruker AdLib istedet."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3688,12 +3806,21 @@ msgstr "Vis objektmerkelapper"
msgid "Show labels for objects on mouse hover"
msgstr "Vis merkelapper for objekter når musa står over dem"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Du mangler 'teenagent.dat'-fila. Hent den ned fra ScummVM-hjemmesiden"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3794,9 +3921,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktiv filtermodus: Nærmeste"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktiver Roland GS-modus"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Legg til spill..."
diff --git a/po/nl_NL.po b/po/nl_NL.po
index 99d1400b04..b5e70af11f 100644
--- a/po/nl_NL.po
+++ b/po/nl_NL.po
@@ -5,17 +5,17 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: ScummVM 1.8.0git\n"
+"Project-Id-Version: ScummVM 1.9.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
-"PO-Revision-Date: 2016-02-21 13:05+0100\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
+"PO-Revision-Date: 2016-07-05 10:07+0200\n"
"Last-Translator: Ben Castricum <scummvm@bencastricum.nl>\n"
"Language-Team: Ben Castricum <scummvm@bencastricum.nl>\n"
"Language: Nederlands\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=iso-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.8.7\n"
+"X-Generator: Poedit 1.8.8\n"
"X-Poedit-SourceCharset: iso-8859-1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -55,15 +55,16 @@ msgstr "Ga omhoog"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Annuleren"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Wilt u dit bestand echt overschrijven?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "Ja"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Driehoek"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Misc"
@@ -205,14 +206,14 @@ msgstr "Reset"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Alle FluidSynth instellingen terugzetten naar de standaard waarden."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -242,15 +243,15 @@ msgstr "Sluiten"
msgid "Mouse click"
msgstr "Muisklik"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Toon toetsenbord"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Toetsen opnieuw koppelen"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Volledig scherm in-/uitschakelen"
@@ -326,8 +327,8 @@ msgstr ""
"De taal van het spel. Dit verandert een Engels spel niet naar een "
"Nederlandse."
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<standaard>"
@@ -349,11 +350,11 @@ msgstr "Platform:"
msgid "Engine"
msgstr "Engine"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Beeld"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -366,7 +367,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Negeer algemene grafische instellingen"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Geluid"
@@ -379,11 +380,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Negeer algemene audio instellingen"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volume"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volume"
@@ -397,218 +398,219 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Negeer algemene volume instellingen"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Negeer algemene MIDI instellingen"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Negeer algemene MIDI instellingen"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Negeer algemene MT-32 instellingen"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Negeer algemene MT-32 instellingen"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Paden"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Paden"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Spel Pad:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Spel Pad:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Extra Pad:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Specificeer pad naar additionele data voor het spel"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Extra Pad:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Bewaar Pad:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Bepaalt waar opgeslagen spellen worden bewaard."
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Bewaar Pad:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Geen"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Standaard"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Selecteer SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Selecteer map met speldata"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Selecteer additionele speldatamap"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Selecteer map voor opgeslagen spellen"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Dit spel-ID is al in gebruik. Kies a.u.b. een andere."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~S~toppen"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Hiermee verlaat u ScummVM."
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "O~v~er..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Geeft informatie over ScummVM."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pties..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Algemene ScummVM opties"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tarten"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Start het geselecteerde spel."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~L~aad Spel..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Laad een eerder opgeslagen spel voor het geselecteerde spel."
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
-msgstr "Spel ~T~oevoegen"
+msgstr "Spel ~T~oevoegen..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr ""
"Houd Shift ingedrukt voor het toevoegen van grote hoeveelheden spellen."
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
-msgstr "Spel ~B~ewerken"
+msgstr "Spel ~B~ewerken..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Verander spel opties"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "Spel ~V~erwijderen"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr ""
"Verwijder dit spel uit de lijst. De spel data bestanden blijven intact."
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~T~oevoegen..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~B~ewerken..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~V~erwijderen"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Zoek in lijst met spellen"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Zoeken:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Laad spel:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Laden"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -616,41 +618,41 @@ msgstr ""
"Wilt u echt de mass game detector draaien? Dit voegt potentieel een groot "
"aantal spellen toe."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kon de opgegeven map niet openen!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM kon geen enkel spel vinden in de opgegeven map!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Kies het spel:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Wilt u echt deze spelconfiguratie verwijderen?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Wilt u het opgeslagen spel laden?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Dit spel ondersteunt het laden van spelen vanaf het startmenu niet."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM heeft geen engine gevonden die in staat was het geselecteerde spel "
"te spelen!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Mass Add..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Opnemen..."
@@ -672,7 +674,7 @@ msgstr ""
#: gui/massadd.cpp:266
#, c-format
msgid "Scanned %d directories ..."
-msgstr "%d directories doorgezocht..."
+msgstr "%d directories doorgezocht ..."
#: gui/massadd.cpp:269
#, c-format
@@ -697,132 +699,132 @@ msgstr "Schakel naar Spel"
msgid "Fast replay"
msgstr "Snelle herhaling"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Nooit"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "elke 5 minuten"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "elke 10 minuten"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "elke 15 minuten"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "elke 30 minuten"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Geen"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Sommige grafische opties konden niet worden toegepast:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "de videomodus kon niet veranderd worden."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "de volledig-scherminstelling kon niet veranderd worden"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "de pixelverhoudinginstelling kon niet veranderd worden"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafische modus:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Render modus:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Speciale ditheringmodi die door sommige games ondersteund worden."
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Volledig-scherm modus"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Pixelverhoudingcorrectie"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Corrigeer de pixelverhouding voor 320x200 spellen."
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Voorkeursapparaat:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Muziekapparaat:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Specificeert het voorkeurs geluidsapparaat of geluidskaartemulator"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Specificeert geluidsapparaat of geluidskaartemulator"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Voorkeursapparaat:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Muziekapparaat:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emulator:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib word in vele spelen voor muziek gebruikt"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Output snelheid:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -830,67 +832,63 @@ msgstr ""
"Hogere waarden geven betere geluidskwaliteit maar worden mogelijk niet "
"ondersteund door uw geluidskaart."
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM Apparaat:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Specificeert het standaard geluidsapparaat voor General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Geen General MIDI muziek gebruiken"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Gebruik eerst beschikbare apparaat"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont wordt ondersteund door FluidSynth en Timidity en sommige "
"geluidskaarten."
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Gemengde AdLib/MIDI modus"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Gebruik zowel MIDI als AdLib geluid"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI gain:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth Instellingen"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 Apparaat:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Specificeert het standaard geluidsapparaat voor Roland MT-32/LAPC1/CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Waarheidsgetrouwe Roland MT-32 (GM emulatie uitschakelen)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -898,16 +896,16 @@ msgstr ""
"Selecteer als u een hardware Roland-compatible geluidsapparaat gekoppeld aan "
"uw computer wilt gebruiken"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Echte Roland MT-32 (geen GM emulatie)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS Device (met MT-32 mappings)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -915,171 +913,187 @@ msgstr ""
"Selecteer dit als u patchmappings wilt om een MT-32 op een Roland GS "
"apparaat te emuleren."
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Geen Roland MT-32 muziek gebruiken"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Spraak en/of tekst:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Spraak"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Tekst"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Beide"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Snelheid tekst:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Spraak en/of text:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Sprk"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Text"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Beide"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Toon tekst en speel spraak af"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Snelheid text:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Muziek volume:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Muziek volume:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Alles Dempen"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "SFX volume:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volume voor speciale geluidseffecten"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "SFX volume:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Spraak volume:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Spraak volume:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth Instellingen"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Thema Pad:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Thema Pad:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Specificeert het pad for aanvullende data voor ScummVM zelf of de spellen."
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Plugins Pad:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Plugins Pad:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Misc"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Thema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI Renderer:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autosave:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autosave:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Toetsen"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "GUI Taal:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Taal van de ScummVM GUI"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "Update controle:"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "Hoe vaak checken op ScummVM updates"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "Controleer nu"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "U dient ScummVM opnieuw op te starten om de wijzigingen te activeren."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
"Er kan niet worden geschreven in de gekozen map. Selecteer a.u.b. een andere."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Selecteer map voor GUI themas"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Selecteer map voor extra bestanden"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Selecteer map voor plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1096,65 +1110,65 @@ msgstr "# volgende"
msgid "add"
msgstr "voeg toe"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Karakter verwijderen"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Num"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Opnemen of Afspelen Spel"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Verwijderen"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Opnemen"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Opnieuw afspelen"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Bewerken"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Auteur:"
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notities"
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Wilt u deze opname echt verwijderen?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Onbekende Auteur"
@@ -1218,7 +1232,7 @@ msgstr "Nieuw spel opslaan"
msgid "Name: "
msgstr "Naam: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Geef een omschrijving voor slot %d:"
@@ -1227,64 +1241,88 @@ msgstr "Geef een omschrijving voor slot %d:"
msgid "Select a Theme"
msgstr "Selecteer een thema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX uitgeschakeld"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX uitgeschakeld"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standaard Renderer"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standaard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Antialiased Renderer"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Antialiased"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM ondersteund nu automatische updates.\n"
+"Hiervoor is wel internet toegang nodig.\n"
+"\n"
+"Wilt u deze functie inschakelen?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(U kunt dit altijd inschakelen in de opties dialoog van de Misc tab)"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "Automatisch controleren op updates"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "Ga verder"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Veld leegmaken"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Engine ondersteunt debug level '%s' niet"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Overslaan"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pauze"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Regel overslaan"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fout tijdens het starten van spel:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr ""
"Kon geen engine vinden die in staat was het geselecteerde spel te spelen"
@@ -1380,17 +1418,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Amber"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "Dagelijks"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "Wekelijks"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "Maandelijks"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<Ongeldige waarde>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Het spel in '%s' lijkt onbekend te zijn."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Raporteer a.u.b. de volgende gegevens aan het ScummVM team samen met de naam"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "van het spel die u probeerde toe te voegen, en haar versie/taal/etc.:"
@@ -1398,11 +1452,11 @@ msgstr "van het spel die u probeerde toe te voegen, en haar versie/taal/etc.:"
msgid "~R~esume"
msgstr "~H~ervatten"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~L~aden"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "Op~s~laan"
@@ -1427,15 +1481,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "S~t~artmenu"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Spel opslaan:"
@@ -1444,15 +1498,16 @@ msgstr "Spel opslaan:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Opslaan"
@@ -1476,13 +1531,13 @@ msgstr ""
"basisinformatie, en voor instructies voor het verkrijgen van verdere "
"assistentie."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~nnuleer"
@@ -1490,24 +1545,24 @@ msgstr "~A~nnuleer"
msgid "~K~eys"
msgstr "~T~oetsen"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kon kleurformaat niet initialiseren."
# can this be changed into "Could not switch to video mode '%s'"?
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kon niet schakelen naar videomodus: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Pixelverhoudinginstelling kon niet toegepast worden."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kon volledig-scherminstelling niet toepassen."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1521,7 +1576,7 @@ msgstr ""
"bestanden naar uw harddisk te kopieren.\n"
"Voor details kijk in de README."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1534,7 +1589,7 @@ msgstr ""
"CD rip programma om te kunnen luisteren naar\n"
"het spelmuziek. Voor details kijk in de README."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1544,7 +1599,7 @@ msgstr ""
"voor basisinformatie, en voor instructies voor het verkrijgen van verdere "
"assistentie."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1555,11 +1610,11 @@ msgstr ""
"instabiel is, en opgeslagen spellen zullen mogelijk niet werken in "
"toekomstige versies van ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Evengoed starten"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib Emulator"
@@ -1640,11 +1695,11 @@ msgstr "FM-Towns Geluid"
msgid "PC-98 Audio"
msgstr "PC-98 Geluid"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "MT-32 Emulator initialiseren"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 Emulator"
@@ -1676,7 +1731,7 @@ msgstr "Wilt u echt stoppen?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Stoppen"
@@ -1761,11 +1816,11 @@ msgstr "Auto-sleep modus is nu"
msgid "Swipe three fingers to the right to toggle."
msgstr "Swipe drie vingers naar rechts om te schakelen."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (geen filters)"
@@ -1780,19 +1835,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normaal (niet schalen)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Pixelverhoudingcorrectie ingeschakeld"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Pixelverhoudingcorrectie uitgeschakeld"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Actieve grafische filter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Venstermodus"
@@ -1825,7 +1880,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~S~luiten"
@@ -2319,20 +2374,36 @@ msgstr ""
"Vergeet niet de 'Verberg werkbalk' te koppelen aan een toets om de hele "
"inventaris te zien."
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Controleren op updates..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr "Kleurenmodus"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr "Gebruik kleurenafbeeldingen"
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr "scanlines"
+
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr "Toon scanlines"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Gebruik originele opslaan/laad schermen"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2361,27 +2432,49 @@ msgstr ""
"Zet muis ondersteuning aan. Maakt het mogelijk om de muis te gebruiken voor "
"bewegen en in spelmenus."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "Gebruik Hercules hires lettertype"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+"Gebruikt het Hercules hires lettertype wanneer het lettertype bestand "
+"beschikbaar is."
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "Pauzeer tijdens invoeren van opdrachten"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"Toont een opdrachtpromptscherm en pauzeert het spel (zoals in SCI) in plaats "
+"van een real-time prompt."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Laad opgeslagen spel:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Laad"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2392,7 +2485,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2403,7 +2496,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2414,7 +2507,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Cutscene bestand '%s' niet gevonden!"
@@ -2445,20 +2538,20 @@ msgstr ""
"Klik OK om ze nu te converteren, anders zult u de volgende keer als u het "
"spel start dit weer gevraagd worden.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Gebruik heldere palet modus"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Gebruik het heldere palet van het spel voor grafische zaken."
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Laden van opgeslagen spel mislukt."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Opslaan van spel in bestand is mislukt."
@@ -2475,7 +2568,7 @@ msgstr "Film snel afspelen"
msgid "Play movies at an increased speed"
msgstr "Speel films sneller af"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Opslaan van spel mislukt."
@@ -2645,55 +2738,63 @@ msgstr ""
"%d origneel opgeslagen spellen zijn succesvol geimporteerd in ScummVM.\n"
"Als u later handmatig origineel opgeslagen spellen wilt importeren dan zult "
"u de\n"
-"ScummVM debug console moeten openen en het commando 'import_savefile' "
+"ScummVM debug console moeten openen en de opdracht 'import_savefile' "
"gebruiken.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "Speel de Myst fly by film"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr "De Myst fly by file werd niet door de originele engine afgespeeld."
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ip Modus Aangezet"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~O~vergangen Aangezet"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "Laat Pagina ~V~allen"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
msgstr "~T~oon Map"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
msgstr "~H~oofdmenu"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~W~ater Effect Aangezet"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Sla de Hall of Records verhaallijnscenes over"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
"Maakt het voor de speler mogelijk om de Hall of Records verhaallijnscenes "
"over te slaan"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Schaal het maken van videos naar het volledige scherm"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Schaal het maken van videos zodat ze het volledige scherm gebruiken"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2702,23 +2803,23 @@ msgstr ""
"Spel opslaan in slot %i mislukt\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Laad bestand"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Spel laden..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Bestand opslaan"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Spel opslaan..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2735,11 +2836,11 @@ msgstr ""
"Klik OK om ze nu te converteren, anders zult u de volgende keer als u het "
"spel start dit weer gevraagd worden.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM heeft al uw opgeslagen spellen succesvol geconverteerd."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2796,37 +2897,45 @@ msgid "Use an alternative game intro (CD version only)"
msgstr ""
"Gebruik een alternatieve versie van de intro (alleen voor de CD versie)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Sla EGA dithering stap over (volledige kleuren achtergronden)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Sla dithering stap in EGA spellen over, beelden worden getoond met volledige "
"kleuren"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Gebruik hoge resolutie beelden"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Gebruik hoge resolutie beelden"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr ""
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Geef de voorkeur aan digitale geluidseffecten"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Geef de voorkeur aan digitale geluidseffecten boven gesynthetiseerde"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Gebruik IMF/Yamaha FB-01 voor MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2834,149 +2943,157 @@ msgstr ""
"Gebruik een IBM Music Feature kaart of eem Yamaha FB-01 FM synth module voor "
"MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Gebruik CD audio"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Gebruik CD audio in plaats van in-game audio, als dat beschikbaar is."
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Gebruik Windows muisaanwijzers"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Gebruik Windows muisaanwijzers (kleiner en monochrome) in plaats van de DOS "
"muisaanwijzers"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Gebruik zilveren muisaanwijzers"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Gebruik de alternative set van zilveren cursors, in plaats van de normale "
"gouden"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "Toon Object Regel"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "Toon de namen van de objecten onderaan het scherm."
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Plaats disk %c en druk knop om verder te gaan."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Kan %s niet vinden, (%c%d) Druk op de knop."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Fout tijdens lezen van disk %c, (%c%d) Druk op de knop."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Spel is gepauzeerd. Druk op de spatiebalk om verder te gaan."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Weet u zeker dat u opnieuw wilt beginnen? (J/N)J"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Weet u zeker dat u wilt stoppen? (J/N)J"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Spelen"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Plaats bewaar/laad speldisk"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "U moet een naam invoeren"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Het spel was NIET opgeslagen (disk vol?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Het spel was NIET geladen"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Opslaan '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Laden '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Geef uw spel een naam"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Selecteer welk opgeslagen spel u wilt laden."
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Spel titel)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~V~orige"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~V~olgende"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Alleen Spraak"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Spraak and Subtitels"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Alleen subtitels"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tekst en Spraak"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Selecteer een vakkundigheidsniveau."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Raadpleeg uw Loom(TM) handleiding voor hulp."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Oefenen"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3513,23 +3630,23 @@ msgstr "Vlieg naar rechts"
msgid "Fly to lower right"
msgstr "Vlieg naar rechts omlaag"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Snap scrollen aan"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Snap scroll uit"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Muziek volume:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Snelheid ondertitels:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3538,7 +3655,7 @@ msgstr ""
"Voor MIDI support is de Roland Upgrade van Lucasarts vereist,\n"
"maar %s ontbreekt. Er wordt nu AdLib gebruikt."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3719,14 +3836,23 @@ msgstr "Toon objectnamen"
msgid "Show labels for objects on mouse hover"
msgstr "Toon labels voor objecten als de muis er over zweeft"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "Gebruik Engels"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr "Gebruik Engels in plaats van Duits voor elke taal anders dan Duits"
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"Het 'teenagent.dat' bestand ontbreekt. U kunt die vinden op de ScummVM "
"website."
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
diff --git a/po/nn_NO.po b/po/nn_NO.po
index 62f7c07beb..d52ab96aaf 100644
--- a/po/nn_NO.po
+++ b/po/nn_NO.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-26 00:37+0100\n"
"Last-Translator: Einar Johan Trøan Sømåen <einarjohants@gmail.com>\n"
"Language-Team: somaen <einarjohants@gmail.com>\n"
@@ -55,15 +55,16 @@ msgstr "Oppover"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Avbryt"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Vil du verkeleg overskrive fila?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "Ja"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Triangel"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Diverse"
@@ -205,14 +206,14 @@ msgstr "Nullstill"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Nullstill alle FluidSynth-instillingar til standardverdiar"
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -241,15 +242,15 @@ msgstr "Steng"
msgid "Mouse click"
msgstr "Musklikk"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Syn Tastatur"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Omkople tastar"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Veksle fullskjerm"
@@ -325,8 +326,8 @@ msgstr ""
"Spelets språk. Dette vil ikkje gjere den spanske versjonen av spelet til ein "
"engelsk versjon"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<standard>"
@@ -348,11 +349,11 @@ msgstr "Plattform:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafikk"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -365,7 +366,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Overstyr globale grafikkinstillingar"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Lyd"
@@ -378,11 +379,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Overstyr globale lydinstillingar"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volum"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volum"
@@ -396,256 +397,257 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Overstyr globale voluminstillingar"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Overstyr globale MIDI-instillingar"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Overstyr globale MIDI-instillingar"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Overstyr globale MT-32-instillingar"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Overstyr globale MT-32-instillingar"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Stiar"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Stiar"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Spelsti:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Spelsti:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Ekstrasti:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Veljer sti til tilleggsdata nytta av spelet"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Ekstrasti:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Lagringssti:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Veljer kor lagra spel vert lagra"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Lagringssti:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ingen"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Standard"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Vel SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Vel mappe med speldata"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Vel mappe med tileggsdata for spelet"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Vel mappe for lagra spel"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Denne spel-IDen er allerede teken. Vær vennleg og vel ein anna."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~A~vslutt"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Avslutt ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "~O~m..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Om ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~V~al..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Endre globale ScummVM-instillingar"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tart"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Start det velde spelet"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~Å~pne..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Åpne eit lagra spel for the velde spelet"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~L~egg til spel..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Hold Shift nede for å legge til fleire"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~R~ediger spel..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Endre spelinstillingar"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~F~jern spel"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Fjern spel frå lista. Speldataene forblir intakte"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~L~egg til spel..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~R~ediger spel..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~F~jern spel"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Søk i spelliste"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Søk:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Åpne spel:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Åpne"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
msgstr ""
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunne ikkje åpne den velde mappa!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM kunne ikkje finne noko spel i den velde mappa!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Vel spelet:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Vil du verkeleg fjerne denne spelkonfigurasjonen?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vil du laste det lagra spelet?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Dette spelet støttar ikkje åpning av lagra spel frå oppstartaren."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM kunne ikkje finne nokon motor som var i stand til å køyre det velde "
"spelet!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Legg til fleire..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -689,132 +691,132 @@ msgstr "Bytt til spel"
msgid "Fast replay"
msgstr ""
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Aldri"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "kvart 5. min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "kvart 10. min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "kvart 15. min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "kvart 30. min"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ingen"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Klarte ikkje å aktivere nokre av grafikkvalendringane:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "Kunne ikkje endre videomodus."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "Fullskjerminstillinga kunne ikkje endrast"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "aspektrate-innstillinga kunne ikkje endrast"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafikkmodus:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Teiknemodus:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Spesielle dithering-modus som støttast av nokre spel"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Fullskjermsmodus"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Aspekt-korrigering"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Rett opp aspekt for 320x200 spel"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Føretrukken eining:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musikkeining:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr ""
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr ""
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musikkeining:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib emulator:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib nyttast til musikk i mange spel"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr ""
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -822,64 +824,60 @@ msgstr ""
"Høgare verdier gir betre lydkvalitet, men støttast kanskje ikkje av "
"lydkortet ditt"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM Eining:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Veljer standard lydeining for General MIDI avspeling"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Ikkje nytt General MIDI musikk"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Nytt første tilgjengelege eining"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "SoundFont støttast av enkelte lydkort, FluidSynth og Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Blanda AdLib/MIDI-modus"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Nytt båe MIDI og AdLib lydskaping"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI gain:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth instillingar"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 Eining:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr "Veljer standard lydeining for Roland MT-32/LAPC1/CM32l/CM64 avspeling"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Ekte Roland MT-32 (deaktiver GM-emulering)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -887,184 +885,200 @@ msgstr ""
"Vel om du vil nytte din Roland-kompatible lydeining som du har tilkopla "
"datamaskina di."
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Ekte Roland MT-32 (ingen GS-emulering)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr ""
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
msgstr ""
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Ikkje nytt Roland MT-32 musikk"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Tekst og Tale:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Tale"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Teksting"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Begge"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Undertekstfart:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Tekst og Tale:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Tale"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Tekst"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Båe"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Vis teksting og spel av tale"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Undertekstfart:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musikkvolum:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musikkvolum:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Demp alle"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Lydeffektvolum:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Spesiallydeffekt volum"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Lydeffektvolum:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Talevolum:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Talevolum:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth instillingar"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Temasti:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Temasti:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Pluginsti:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Pluginsti:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Div"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI-teiknar:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autolagre:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autolagre:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Tastar"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "GUI-språk:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Språk i ScummVM-GUIet"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Du må starte ScummVM på nytt for at endringane skal tre i kraft."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Den velde mappa kan ikkje skrivast til. Vennlegst vel ein annan."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Vel ei mappe for GUI-tema:"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Vel ei mappe for ekstra filer"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Vel ei mappe for plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1081,65 +1095,65 @@ msgstr "# neste"
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr ""
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Tal"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Slett"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr ""
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Rediger"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Forfattar: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Notatar: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr ""
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Ukjend Forfattar"
@@ -1203,7 +1217,7 @@ msgstr "Lag eit nytt lagra spel"
msgid "Name: "
msgstr "Namn:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1212,64 +1226,85 @@ msgstr ""
msgid "Select a Theme"
msgstr "Vel eit tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Deaktivert GFX"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Deaktivert GFX"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standardteiknar"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Kantutjevna teiknar"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Kantutjevna"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "SJå etter oppdateringar..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Tøm verdi"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Motoren støttar ikkje debug-nivå '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Meny"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Hopp over"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pause"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Hopp over linje"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Feil under køyring av spel:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Kunne ikkje finne nokon motor som kunne køyre det velde spelet."
@@ -1364,17 +1399,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Raudgul"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Tøm verdi"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Spelet i '%s' ser ut til å vere ukjend."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Vennlegst rapporter følgjande data til ScummVM-teamet, saman med namnet"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "på spelet du prøvde å leggje til, samt versjon/språk/etc.:"
@@ -1382,11 +1434,11 @@ msgstr "på spelet du prøvde å leggje til, samt versjon/språk/etc.:"
msgid "~R~esume"
msgstr "~F~ortsett"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~Å~pne"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~L~agre"
@@ -1411,15 +1463,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Tilbake til Oppsta~r~tar"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Lagra spel:"
@@ -1428,15 +1480,16 @@ msgstr "Lagra spel:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Lagre"
@@ -1460,13 +1513,13 @@ msgstr ""
"grunnlegjande informasjon, og for instruskjonar om korleis du kan få "
"ytterlegare hjelp."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~vbryt"
@@ -1474,23 +1527,23 @@ msgstr "~A~vbryt"
msgid "~K~eys"
msgstr "~T~astar"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Høgkvalitetslyd (treigare) (omstart)"
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunne ikkje veksle til videomodus: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kunne ikkje slå på aspekt-korrigering"
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunne ikkje aktiver fullskjermsinnstilling."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1504,7 +1557,7 @@ msgstr ""
"datafilane til harddisken din istaden. \n"
"Sjå README-fila for detaljar."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1513,7 +1566,7 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1523,7 +1576,7 @@ msgstr ""
"grunnlegjande informasjon, og for instruskjonar om korleis du kan få "
"ytterlegare hjelp."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1533,11 +1586,11 @@ msgstr ""
"ennå. Derfor er det sannsynleg at det er ustabilt, og det er mogleg at lagra "
"spel ikkje vil fungere med fremtidige versjonar av ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Start allikevel"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib Emulator"
@@ -1618,11 +1671,11 @@ msgstr "FM-Towns Lyd"
msgid "PC-98 Audio"
msgstr "PC-98 Lyd"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Initialiserar MT-32 Emulator"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 Emulator"
@@ -1654,7 +1707,7 @@ msgstr "Vil du verkeleg avslutte?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Avslutt"
@@ -1739,11 +1792,11 @@ msgstr ""
msgid "Swipe three fingers to the right to toggle."
msgstr "Sveip tre fingre til høgre for å veksle"
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (Ingen filtrering)"
@@ -1758,19 +1811,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (ikkje skaler)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Aspekt-korrigering aktivert"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Aspekt-korrigering ikkje aktivert"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktivt grafikkfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Vindusmodus"
@@ -1803,7 +1856,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~L~ukk"
@@ -2294,20 +2347,38 @@ msgstr ""
"Ikkje gløym å kople ein tast til 'Skjul verktøylinje' for å se heile "
"inventaret"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "SJå etter oppdateringar..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Fargeblindmodus"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Syn objektmerkelappar"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Nytt opprinnelege skjermar for lagring/lasting"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2331,27 +2402,46 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules Grønn"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Gjenopprett spel:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Gjenopprett"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2359,7 +2449,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2367,7 +2457,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2375,7 +2465,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr ""
@@ -2406,20 +2496,20 @@ msgstr ""
"Trykk OK for å konvertere dei no, ellers kjem du til å verte spurt neste "
"gong du startar spelet.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Nytt lys palett-modus"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr ""
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Kunne ikkje laste lagra spel frå fil."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Klarte ikkje lagre speltilstand til fil."
@@ -2436,7 +2526,7 @@ msgstr "Rask filmfart"
msgid "Play movies at an increased speed"
msgstr "Spel filmar med auka hastighet"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Klarte ikkje lagre spel"
@@ -2592,49 +2682,59 @@ msgid ""
"\n"
msgstr ""
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ipmodus aktivert"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~O~vergangar aktivert"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr ""
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~S~yn Kart"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "Hoved~m~eny"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~V~anneffekt aktivert"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr ""
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2643,23 +2743,23 @@ msgstr ""
"Kan ikkje lagre spel i spor %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Last fil:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Lastar spel..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Lagra fil:"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Lagrar spel..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2669,11 +2769,11 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked next time.\n"
msgstr ""
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr ""
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2725,35 +2825,44 @@ msgstr "Alternativ intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "Nytt alternativ spillåpning (Kun CD-versjon)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Nytt høgoppløyseleg grafikk"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Nytt høgoppløyseleg grafikk/innhald"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Aktiver Roland GS-modus"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Foretrekk digitale lydeffekter"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Nytt IMF/Yamaha FB-01 til MIDI-output"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2761,145 +2870,154 @@ msgstr ""
"Nytt eit IBM Music Feature-kort eller ein Yamaha FB-01 FM synth modul for "
"MIDI avspeling"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Nytt CD-lyd"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Nytt CD-lyd istaden for spellyd, om den er tilgjengeleg"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Nytt Windospeikarar"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr "Nytt windowspeikarane (mindre og monokrome) istaden for DOS-peikarane"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Nytt sølvpeikarar"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr "Nytt det alternative settet med sølvpeikarar, istaden for dei gylne"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Syn objektmerkelappar"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Sett inn disk %c og trykk på knappen for å fortsette."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr ""
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr ""
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Spelet er pausa. Trykk MELLOMROM for å fortsette."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Er du sikker på at du vil starte på nytt (J/N)J"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Er du sikker på at du vil avslutte (J/N)J"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Spel"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Sett in lagre/laste speldisk"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Du må skrive eit namn"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Spelet vart IKKJE lagra (full disk?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Spelet vart IKKJE lasta"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Lagrar '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Lastar '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Namngi det LAGRA spelet"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Vel eit spel for LASTING"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Speltittel)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~F~orrige"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~N~este"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Berre Tale"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tale og undertekstar"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Berre undertekstar"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tekst & Tale"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr ""
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Sjå i Loom(TM)-manualen for hjelp."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Øving"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3436,30 +3554,30 @@ msgstr "Fly til høgre"
msgid "Fly to lower right"
msgstr "Fly til nedre høgre"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr ""
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Musikkvolum:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Subtitle speed: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
"but %s is missing. Using AdLib instead."
msgstr ""
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3631,12 +3749,21 @@ msgstr "Syn objektmerkelappar"
msgid "Show labels for objects on mouse hover"
msgstr "Syn merkelappar for objekt når musa er over dei"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Du mangler fila 'teenagent.dat'. Skaff den frå ScummVM-heimesida"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3717,9 +3844,6 @@ msgstr ""
#~ msgid "Current display mode"
#~ msgstr "Gjeldende videomodus:"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktiver Roland GS-modus"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Legg til spill..."
diff --git a/po/pl_PL.po b/po/pl_PL.po
index 6546259ade..7e1ab14800 100644
--- a/po/pl_PL.po
+++ b/po/pl_PL.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-20 23:43+0100\n"
"Last-Translator: Micha³ Zi±bkowski <mziab@o2.pl>\n"
"Language-Team: Grajpopolsku.pl <grajpopolsku@gmail.com>\n"
@@ -58,15 +58,16 @@ msgstr "W górê"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Anuluj"
@@ -105,7 +106,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Na pewno chcesz nadpisaæ ten plik?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -115,7 +116,7 @@ msgid "Yes"
msgstr "Tak"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -176,7 +177,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Trójk±t"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Ró¿ne"
@@ -208,14 +209,14 @@ msgstr "Reset"
msgid "Reset all FluidSynth settings to their default values."
msgstr "Przywróæ domy¶lne warto¶ci wszystkich ustawieñ FluidSynth."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -244,15 +245,15 @@ msgstr "Zamknij"
msgid "Mouse click"
msgstr "Klikniêcie"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Wy¶wietl klawiaturê"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Dostosuj klawisze"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "W³±cz/wy³±cz pe³ny ekran"
@@ -326,8 +327,8 @@ msgid ""
"English"
msgstr "Jêzyk gry. Nie zmieni to hiszpañskiej wersji gry w angielsk±."
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<domy¶lne>"
@@ -349,11 +350,11 @@ msgstr "Platforma:"
msgid "Engine"
msgstr "Silnik"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafika"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "Grafika"
@@ -366,7 +367,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "U¿yj w³asnych ustawieñ grafiki"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "D¼wiêk"
@@ -379,11 +380,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "U¿yj w³asnych ustawieñ d¼wiêku"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "G³o¶no¶æ"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "G³o¶no¶æ"
@@ -397,255 +398,256 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "U¿yj w³asnych ustawieñ g³o¶no¶ci"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "U¿yj w³asnych ustawieñ MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "U¿yj w³asnych ustawieñ MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "U¿yj w³asnych ustawieñ MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "U¿yj w³asnych ustawieñ MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "¦cie¿ki"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "¦cie¿ki"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "¦cie¿ka gry:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "¦cie¿ka gry:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "¦c. dodatków:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Okre¶la ¶cie¿kê dodatkowych danych gry"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "¦c. dodatków:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "¦cie¿ka zapisów:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Okre¶la gdzie zapisywaæ stan gry"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "¦cie¿ka zapisów:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Brak"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Domy¶lnie"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Wybierz SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Wybierz katalog z plikami gry"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Wybierz dodatkowy katalog gry"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Wybierz katalog dla zapisów"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Identyfikator jest ju¿ zajêty. Wybierz inny."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~Z~akoñcz"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Zakoñcz ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "I~n~formacje..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Ksi±¿ka ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pcje..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Zmieñ ustawienia ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tart"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Rozpocznij wybran± grê"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~W~czytaj..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Wczytaj zapis wybranej gry"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~D~odaj grê..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Przytrzymaj Shift, by dodawaæ zbiorowo"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~dytuj grê..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Zmieñ opcje gry"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~U~suñ grê"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Usuwa grê z listy. Pliki gry pozostaj± nietkniête"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~D~odaj grê..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~dytuj grê..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~U~suñ grê"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Wyszukaj grê na li¶cie"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Szukaj"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Wczytaj grê:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Wczytaj"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
msgstr ""
"Chcesz uruchomiæ masowy detektor gier? Mo¿e dodaæ wiele tytu³ów do listy"
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM nie mo¿e otworzyæ katalogu!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM nie znalaz³ ¿adnej gry w tym katalogu!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Wybierz grê:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Na pewno chcesz usun±æ tê grê z konfiguracji?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Chcesz wczytaæ zapis stanu gry?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Ta gra nie wspiera wczytywania z launchera."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM nie znalaz³ silnika zdolnego uruchomiæ wybran± grê!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Przeszukaj..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Nagraj..."
@@ -688,132 +690,132 @@ msgstr "Prze³±cz do gry"
msgid "Fast replay"
msgstr "Szybka powtórka"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Nigdy"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "co 5 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "co 10 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "co 15 min"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "co 30 min"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Brak"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Nie uda³o siê zastosowaæ czê¶ci zmian opcji grafiki:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "nie uda³o siê zmieniæ trybu wideo."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "nie uda³o siê zmieniæ trybu pe³noekranowego"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "nie uda³o siê zmieniæ formatu obrazu"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Tryb grafiki:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Renderer:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Specjalne tryby ditheringu wspierane przez niektóre gry"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Pe³ny ekran"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Korekcja formatu obrazu"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Korekcja formatu obrazu dla gier 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Pref. urz±dzenie:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Urz. muzyczne:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Okre¶la preferowane urz±dzenie d¼wiêkowe lub emulator karty d¼wiêkowej"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Okre¶la wyj¶ciowe urz±dzenie d¼wiêkowe lub emulator karty d¼wiêkowej"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Pref. urz±dzenie:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Urz. muzyczne:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Emulator AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib jest u¿ywany do muzyki w wielu grach"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Czêst. wyj.:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -821,67 +823,63 @@ msgstr ""
"Wy¿sze warto¶ci daj± lepsz± jako¶æ d¼wiêku, ale mog± byæ nieobs³ugiwane "
"przez twoj± kartê d¼wiêkow±"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Urz±dzenie GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Okre¶la domy¶lne urz±dzenie d¼wiêkowe dla wyj¶cia General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Nie u¿ywaj muzyki General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "U¿yj pierwszego dostêpnego urz±dzenia"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont jest wspierany przez niektóre karty d¼wiêkowe, FluidSynth i "
"Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Tryb miksowanego AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "U¿ywaj obu generatorów d¼wiêku, MIDI i AdLib, jednocze¶nie"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Wzm. MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "Ustawienia FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Urz±dzenie MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Okre¶la domy¶lne urz±dzenie d¼wiêku dla wyj¶cia Roland MT-32/LAPC1/CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Prawdziwy Roland MT-32 (wy³±cz emulacjê GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -889,16 +887,16 @@ msgstr ""
"Zaznacz, je¶li chcesz u¿ywaæ swojej prawdziwej karty kompatybilnej z Roland "
"pod³±czonej do twojego komputera"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Prawdziwy Roland MT-32 (brak emulacji GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland w trybie GS (w³±cz mapowanie MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -906,169 +904,185 @@ msgstr ""
"Zaznacz, je¶li chcesz w³±czyæ ³atki mapowania pozwalaj±ce na emulacjê MT-32 "
"na urz±dzeniu Roland GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Nie u¿ywaj muzyki Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Tekst i mowa:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Mowa"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Napisy"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Oba"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Prêd. napisów:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Tekst i mowa:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Mowa"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Napisy"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Oba"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Wy¶wietlaj napisy i odtwarzaj mowê"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Prêd. napisów:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "G³o¶no¶æ muzyki:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "G³o¶no¶æ muzyki:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Wycisz"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "G³. efekt. d¼w.:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "G³o¶no¶æ efektów d¼w."
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "G³. efekt. d¼w.:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "G³o¶no¶æ mowy:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "G³o¶no¶æ mowy:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "Ustawienia FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "¦cie¿ka stylu:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "¦cie¿ka stylu:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr "Okre¶la ¶cie¿kê dla dodatkowych danych dla wszystkich gier lub ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "¦cie¿ka wtyczek:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "¦cie¿ka wtyczek:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Ró¿ne"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Styl:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Renderer interf.:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autozapis:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autozapis:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Klawisze"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Jêzyk interfejsu:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Jêzyk interfejsu ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Musisz zrestartowaæ ScummVM, by zmiany zosta³y uwzglêdnione."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "Ten katalog jest zabezpieczony przed zapisem. Wybierz inny."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Wybierz katalog dla stylów GUI."
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Wybierz katalog dla dodatkowych plików"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Wybierz katalog dla wtyczek"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1085,65 +1099,65 @@ msgstr "# nastêpny"
msgid "add"
msgstr "dodaj"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Usuñ znak"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Num"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Nagrywanie/odtwarzanie rozgrywki"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Skasuj"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Nagrywaj"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Odtwarzaj"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Edytuj"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Autor: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Uwagi: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Na pewno chcesz usun±æ to nagranie?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Nieznany autor"
@@ -1207,7 +1221,7 @@ msgstr "Stwórz nowy zapis"
msgid "Name: "
msgstr "Nazwa: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Podaj opis dla slotu %d:"
@@ -1216,64 +1230,85 @@ msgstr "Podaj opis dla slotu %d:"
msgid "Select a Theme"
msgstr "Wybierz styl"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Wy³±czona grafika"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Wy³±czona grafika"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standardowy renderer"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standardowy"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Wyg³adzany renderer"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Wyg³adzany"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Sprawd¼ aktualizacjê..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Wyczy¶æ"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Silnik nie wspiera poziomu debugowania '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Pomiñ"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Wstrzymaj"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Pomiñ liniê"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "B³±d podczas uruchamiania gry:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Nie uda³o siê znale¼æ silnika zdolnego do uruchomienia zaznaczonej gry"
@@ -1368,16 +1403,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Bursztynowy Hercules"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Wyczy¶æ"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Gra w '%s' wygl±da na nieznan±."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "Przeka¿ poni¿sze dane zespo³owi ScummVM razem z nazw±"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "gry, któr± próbowa³e¶ dodaæ oraz jej wersj±, jêzykiem itd.:"
@@ -1385,11 +1437,11 @@ msgstr "gry, któr± próbowa³e¶ dodaæ oraz jej wersj±, jêzykiem itd.:"
msgid "~R~esume"
msgstr "~W~znów"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~W~czytaj"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~Z~apisz"
@@ -1414,15 +1466,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~P~owrót do launchera"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Zapis:"
@@ -1431,15 +1483,16 @@ msgstr "Zapis:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Zapisz"
@@ -1462,13 +1515,13 @@ msgstr ""
"Zapis stanu gry nie powiód³ siê (%s)! Aby uzyskaæ podstawowe informacje oraz "
"dowiedzieæ jak szukaæ dalszej pomocy, sprawd¼ plik README."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~A~nuluj"
@@ -1476,23 +1529,23 @@ msgstr "~A~nuluj"
msgid "~K~eys"
msgstr "~K~lawisze"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Nie uda³o siê zainicjalizowaæ formatu kolorów."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Nie uda³o siê prze³±czyæ w tryb wideo: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Nie uda³o siê zastosowaæ ustawienia formatu obrazu."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Nie uda³o siê zastosowaæ ustawienia pe³nego ekranu."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1504,7 +1557,7 @@ msgstr ""
"znane problemów. St±d zalecane jest skopiowanie plików gry na twardy dysk.\n"
"Dalsze informacje s± dostêpne w pliku README."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1516,7 +1569,7 @@ msgstr ""
"skopiowaæ na dysk za pomoc± odpowiedniego rippera CD audio.\n"
"Dalsze informacje s± dostêpne w pliku README."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1525,7 +1578,7 @@ msgstr ""
"Odczyt stanu gry nie powiód³ siê (%s)! Aby uzyskaæ podstawowe informacje "
"oraz dowiedzieæ jak szukaæ dalszej pomocy, sprawd¼ plik README."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1535,11 +1588,11 @@ msgstr ""
"ScummVM. W zwi±zku z tym mo¿e byæ ona niestabilna, a wszelkie zapisy, "
"których dokonasz, mog± byæ nieobs³ugiwane w przysz³ych wersjach ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "W³±cz mimo tego"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Emulator AdLib"
@@ -1620,11 +1673,11 @@ msgstr "D¼wiêk FM-Towns"
msgid "PC-98 Audio"
msgstr "D¼wiêk PC-98"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Inicjalizacja emulatora MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Emulator MT-32"
@@ -1656,7 +1709,7 @@ msgstr "Na pewno chcesz wyj¶æ?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Zakoñcz"
@@ -1741,11 +1794,11 @@ msgstr "Tryb automatycznego przeci±gania jest"
msgid "Swipe three fingers to the right to toggle."
msgstr "Przesuñ trzema palcami, ¿eby zmieniæ."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (bez filtrowania)"
@@ -1760,19 +1813,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Zwyk³y (bez skalowania)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "W³±czono korekcjê formatu obrazu"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Wy³±czono korekcjê formatu obrazu"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktywny filtr graficzny:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Okno"
@@ -1805,7 +1858,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~Z~amknij"
@@ -2295,20 +2348,38 @@ msgstr ""
"Nie zapomnij przypisaæ klawisza 'Ukryj pasek narzêdzi', by widzieæ ca³y "
"ekwipunek"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Sprawd¼ aktualizacjê..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Tryb dla daltonistów"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Poka¿ etykiety obiektów"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "U¿yj oryginalnych ekranów odczytu/zapisu"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM"
@@ -2336,27 +2407,46 @@ msgstr ""
"W³±cza obs³ugê myszki. Pozwala na u¿ycie myszki do przemieszczania i w menu "
"gry."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Zielony Hercules"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Wznów grê:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Wznów"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2367,7 +2457,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2378,7 +2468,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2389,7 +2479,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Nie znaleziono pliku przerywnika '%s'!"
@@ -2419,20 +2509,20 @@ msgstr ""
"Naci¶nij OK, ¿eby je teraz przekonwertowaæ. W przeciwnym wypadku zostaniesz "
"zapytany ponownie przy nastêpnym w³±czeniu gry.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "U¿yj trybu jasnej palety"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Wy¶wietlaj grafikê za pomoc± jasnej palety gry"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Nie uda³o siê wczytaæ stanu gry z pliku."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Nie uda³o siê zapisaæ stanu gry do pliku."
@@ -2449,7 +2539,7 @@ msgstr "Przy¶pieszone filmy"
msgid "Play movies at an increased speed"
msgstr "Odtwarzaj filmy ze zwiêkszon± prêdko¶ci±"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Nie uda³o siê zapisaæ stanu gry"
@@ -2621,49 +2711,59 @@ msgstr ""
"debugowania ScummVM i u¿yæ komendy 'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~T~ryb turbo aktywny"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~P~rzej¶cia w³±czone"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~O~pu¶æ stronê"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~P~oka¿ mapê"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~M~enu g³ówne"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~E~fekty wody w³±czone"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Pomiñ scenki storyboardowe w Hali Rekordów"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "Pozwala graczowi na pomijanie scenek storyboardowych w Hali Rekordów"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Skaluj filmy making of na pe³ny ekran"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Skaluj filmy making of, by wype³nia³y ca³y ekran"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2672,23 +2772,23 @@ msgstr ""
"Nie mo¿na zapisaæ w slocie %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "Wczytaj plik"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Wczytywanie stanu gry..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "Zapisz plik"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Zapisywanie stanu gry..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2704,11 +2804,11 @@ msgstr ""
"Naci¶nij OK, ¿eby je teraz przekonwertowaæ. W przeciwnym wypadku zostaniesz "
"zapytany ponownie przy nastêpnym w³±czeniu gry.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM pomy¶lnie przekonwertowa³ wszystkie twoje zapisy."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2764,36 +2864,45 @@ msgstr "Alternatywne intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "U¿yj alternatywnego intra (tylko dla wersji CD)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Pomiñ dithering EGA (t³a w pe³nym kolorze)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"Pomiñ dithering w grach EGA, grafika bêdzie wy¶wietlana w pe³nym kolorze"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "W³±cz grafikê wysokiej rozdzielczo¶ci"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "W³±cz grafikê/zawarto¶æ wysokiej rozdzielczo¶ci"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "W³±cz tryb Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Preferuj cyfrowe efekty d¼wiêkowe"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Preferuj cyfrowe efekty d¼wiêkowe zamiast syntezowanych"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "U¿yj IMF/Yamaha FB-01 dla wyj¶cia MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2801,147 +2910,156 @@ msgstr ""
"U¿yj karty IBM Music Feature lub modu³u syntezy FM Yamaha FB-01 dla wyj¶cia "
"MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "U¿yj CD audio"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "U¿yj CD audio zamiast muzyki w grze, je¶li jest dostêpne"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "U¿yj windowsowych kursorów"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"U¿yj windowsowych kursorów (mniejsze i monochromatyczne) zamiast DOS-owych"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "U¿yj srebrnych kursorów"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"U¿yj alternatywnego zestawu srebrnych kursorów zamiast zwyk³ych z³otych"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Poka¿ etykiety obiektów"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "W³ó¿ dysk %c i naci¶nij przycisk, aby kontynuowaæ."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Nie znaleziono %s, (%c%d). Naci¶nij przycisk."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "B³±d podczas odczytu dysku %c, (%c%d). Naci¶nij przycisk."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Gra wstrzymana. Naci¶nij spacjê, aby wznowiæ."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Na pewno chcesz zrestartowaæ? (T/N)T"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Na pewno chcesz wyj¶æ? (T/N)T"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Uruchom"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "W³ó¿ dysk zapisu"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Musisz podaæ nazwê"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "NIE zapisano stanu gry (brak miejsca?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "NIE wczytano gry"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Zapisywanie '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Wczytywanie '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Podaj nazwê zapisu"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Wybierz zapis do wczytania"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Tytu³ gry)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~P~oprzednia"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~N~astêpna"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Tylko mowa"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Mowa i napisy"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Tylko napisy"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Mowa i napisy"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Wybierz poziom umiejêtno¶ci."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Pomocy szukaj w instrukcji do³±czonej do Loom(TM)."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Trening"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Ekspert"
@@ -3478,23 +3596,23 @@ msgstr "Leæ w prawo"
msgid "Fly to lower right"
msgstr "Leæ w dó³, w prawo"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Przesuwanie skokowe w³±czone"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Przesuwanie skokowe wy³±czone"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "G³o¶no¶æ muzyki: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Prêd. napisów: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3503,7 +3621,7 @@ msgstr ""
"Natywne wsparcie MIDI wymaga aktualizacji Rolanda od LucasArts,\n"
"ale brakuje %s. Prze³±czam na tryb AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3688,12 +3806,21 @@ msgstr "Poka¿ etykiety obiektów"
msgid "Show labels for objects on mouse hover"
msgstr "Poka¿ etykiety obiektów przy najechaniu myszk±"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Nie masz pliku \"teenagent.dat\". Pobierz go ze strony ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3792,9 +3919,6 @@ msgstr "U¿yj wideo MPEG z wersji DVD zamiast AVI ni¿szej rozdzielczo¶ci"
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktywny tryb filtru: najbli¿szy s±siad"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "W³±cz tryb Roland GS"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Dodaj grê..."
diff --git a/po/pt_BR.po b/po/pt_BR.po
index b42ccf2bff..41a8ad15c7 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2011-10-21 21:30-0300\n"
"Last-Translator: Saulo Benigno <saulobenigno@gmail.com>\n"
"Language-Team: ScummBR (www.scummbr.com) <scummbr@yahoo.com.br>\n"
@@ -57,15 +57,16 @@ msgstr "Acima"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Cancelar"
@@ -105,7 +106,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Você realmente quer excluir este jogo salvo?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -115,7 +116,7 @@ msgid "Yes"
msgstr "Sim"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -179,7 +180,7 @@ msgstr ""
msgid "Triangle"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Outros"
@@ -211,14 +212,14 @@ msgstr ""
msgid "Reset all FluidSynth settings to their default values."
msgstr ""
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -247,15 +248,15 @@ msgstr "Fechar"
msgid "Mouse click"
msgstr "Clique do mouse"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Mostrar teclado"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Remapear teclas"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
#, fuzzy
msgid "Toggle fullscreen"
msgstr "Habilita Tela Cheia"
@@ -330,8 +331,8 @@ msgid ""
"English"
msgstr "Idioma do jogo. Isto não irá passar seu jogo Inglês para Português"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<padrão>"
@@ -354,11 +355,11 @@ msgstr "Sistema:"
msgid "Engine"
msgstr "Examinar"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Gráficos"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -371,7 +372,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Sobrepor configuração global de gráficos"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Áudio"
@@ -384,11 +385,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Sobrepor configuração global de áudio"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volume"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volume"
@@ -402,217 +403,218 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Sobrepor configuração global de volume"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Sobrepor configuração global de MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Sobrepor configuração global de MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Sobrepor configuração global de MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Sobrepor configuração global de MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Pastas"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Pastas"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Pasta do Jogo:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Pasta do Jogo:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Pasta de Extras"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Especifique a pasta para dados utilizados no jogo"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Pasta de Extras"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Pasta para Salvar"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Especifique onde guardar seus jogos salvos"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Pasta para Salvar"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Nenhum(a)"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Padrão"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Selecione o SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Selecione a pasta com os arquivos do jogo"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Selecione a pasta adicional do jogo"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Selecione a pasta para os jogos salvos"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Este código já esta sendo utilizado. Por favor, escolha outro."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~S~air"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Sair do ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "So~b~re..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Sobre o ScumnmVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~O~pções"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Alterar opções globais do ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~I~niciar"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Iniciar jogo selecionado"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~C~arregar"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Carregar jogo salvo do jogo selecionado"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~A~dicionar Jogo..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Segure Shift para Multi-Adição"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "~E~ditar Jogo..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Alterar opções do jogo"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~R~emover Jogo"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr ""
"Remover jogo da lista. Os arquivos de dados do jogo permanecem intactos"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~A~dicionar Jogo..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "~E~ditar Jogo..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~R~emover Jogo"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Pesquisar na lista de jogos"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Pesquisar:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Carregar jogo:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Carregar"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -620,42 +622,42 @@ msgstr ""
"Você realmente deseja adicionar vários jogos ao mesmo tempo? Isso poderá "
"resultar em uma adição gigantesca de jogos."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM não conseguiu abrir a pasta especificada!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM não encontrou nenhum jogo na pasta especificada!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Escolha o jogo:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Você deseja realmente remover a configuração deste jogo?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
#, fuzzy
msgid "Do you want to load saved game?"
msgstr "Você deseja carregar ou salvar o jogo?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Este jogo não suporta abrir jogos a partir do menu principal."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM não conseguiu encontrar qualquer programa capaz de rodar o jogo "
"selecionado!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Multi-Adição..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -704,132 +706,132 @@ msgstr "Trocar"
msgid "Fast replay"
msgstr "Modo rápido"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Nunca"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "a cada 5 mins"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "a cada 10 mins"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "a cada 15 mins"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "a cada 30 mins"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Nenhum(a)"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Falha ao aplicar algumas mudanças nas opções de gráfico:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "o modo de vídeo não pôde ser alterado."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "a configuração de tela cheia não pôde ser mudada"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "a configuração de proporção não pôde ser mudada"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Modo gráfico:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Renderização"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Modos especiais de dithering suportados por alguns jogos"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Modo Tela Cheia"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Correção de proporção"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Correção de proporção para jogos 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Dispositivo pref.:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Disp. de música:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Especifica o dispositivo de som preferido ou emulador de placa de som"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Especifica o dispositivo de saída de som ou emulador de placa de som"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Dispositivo pref.:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Dispositivo de música:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "Emulador AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib é utilizado para música em vários jogos"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Taxa de saída:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -837,66 +839,62 @@ msgstr ""
"Maior valor especifica melhor qualidade de som, mas pode não ser suportado "
"por sua placa de som"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "Dispositivo GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Especifique o dispositivo de som padrão para a saída General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Não usar música General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Usar o primeiro dispositivo disponível"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "SoundFont é suportado por algumas placas de som, FluidSynth e Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Mixar AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Usar MIDI e AdLib juntos na geração de som"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "Ganho MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr ""
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Dispositivo MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Especifique o dispositivo de som padrão para a saída Roland MT-32/LAPC1/"
"CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Roland MT-32 real (desligar emulação GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -904,187 +902,203 @@ msgstr ""
"Verifique se você quer usar o seu dispositivo de hardware de som compatível "
"com Roland"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Roland MT-32 real (sem emulação GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
#, fuzzy
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland MT-32 real (desligar emulação GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
msgstr ""
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Não usar música Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Texto e Voz:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Voz"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Legendas"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Ambos"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Rapidez legendas:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Texto e Voz:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Voz"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Legs"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Ambos"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Mostrar legenda e vozes (dublagem)"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Velocidade das legendas:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Volume da Música:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Volume da Música:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Mudo"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "Volume dos Sons:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volume dos efeitos sonoros especiais"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "Volume dos Sons:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Volume da Voz:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Volume da Voz:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr ""
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Pasta do Tema"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Pasta do Tema"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Especifica a pasta para os dados adicionais usados por todos os jogos ou "
"ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Pasta de Plugins:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Pasta de Plugins:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Outros"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "Renderizador GUI:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Auto-Salvar:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Auto-Salvar:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Teclas"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Idioma do GUI:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Linguagem do ScummVM GUI"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Você tem que reiniciar o ScummVM para funcionar."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "O diretório escolhido não pode ser usado. Por favor, selecione outro."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Selecione a pasta para os temas da Interface de Uso Gráfico"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Selecione a pasta para os arquivos extras"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Selecione a pasta para os plugins"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1101,68 +1115,68 @@ msgstr ""
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
#, fuzzy
msgid "Delete char"
msgstr "Excluir"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr ""
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Excluir"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
#, fuzzy
msgid "Playback"
msgstr "Jogar"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr ""
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr ""
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr ""
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
#, fuzzy
msgid "Do you really want to delete this record?"
msgstr "Você realmente quer excluir este jogo salvo?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
#, fuzzy
msgid "Unknown Author"
msgstr "Erro desconhecido"
@@ -1230,7 +1244,7 @@ msgstr "Falha ao salvar o jogo"
msgid "Name: "
msgstr "Nome:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1239,68 +1253,89 @@ msgstr ""
msgid "Select a Theme"
msgstr "Selecione um Tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "GFX desabilitado"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "GFX desabilitado"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
#, fuzzy
msgid "Standard Renderer"
msgstr "Renderizador padrão (16bpp)"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
#, fuzzy
msgid "Standard"
msgstr "Padrão (16bpp)"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
#, fuzzy
msgid "Antialiased Renderer"
msgstr "Renderizador Anti-Serrilhamento (16bpp)"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
#, fuzzy
msgid "Antialiased"
msgstr "Anti-Serrilhamento (16bpp)"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Procurar por Atualizações..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Limpar valor"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Esse programa não suporta o nível de debug '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Menu"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Pular"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Pausar"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Pula linha"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Erro ao executar o jogo:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr ""
"Não foi possível encontrar qualquer programa capaz de rodar o jogo "
@@ -1397,17 +1432,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules Amber"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Limpar valor"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "O jogo em '% s' parece ser desconhecido."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Por favor, informe os seguintes dados para a equipe ScummVM junto com o nome"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "do jogo que você tentou adicionar e sua versão/idioma/etc.:"
@@ -1415,11 +1467,11 @@ msgstr "do jogo que você tentou adicionar e sua versão/idioma/etc.:"
msgid "~R~esume"
msgstr "~V~oltar ao jogo"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~C~arregar"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~S~alvar"
@@ -1444,15 +1496,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~V~oltar ao menu"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Salvar jogo:"
@@ -1461,15 +1513,16 @@ msgstr "Salvar jogo:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Salvar"
@@ -1493,13 +1546,13 @@ msgstr ""
"Por favor, consulte o README para obter informações básicas, e para obter "
"instruções sobre como obter assistência adicional."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "~C~ancelar"
@@ -1507,23 +1560,23 @@ msgstr "~C~ancelar"
msgid "~K~eys"
msgstr "~T~eclas"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Não foi possível inicializar o formato de cor."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Não foi possível alternar o modo de vídeo atual:"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Não foi possível aplicar a correção de proporção"
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Não foi possível aplicar a configuração de tela cheia."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1537,7 +1590,7 @@ msgstr ""
"os arquivos de dados para o disco rígido.\n"
"Consulte o arquivo README para mais detalhes."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1551,7 +1604,7 @@ msgstr ""
"para ouvir a música do jogo.\n"
"Consulte o arquivo README para mais detalhes."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, fuzzy, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1561,7 +1614,7 @@ msgstr ""
"Por favor, consulte o README para obter informações básicas, e para obter "
"instruções sobre como obter assistência adicional."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1571,11 +1624,11 @@ msgstr ""
"suportado pelo ScummVM. Como tal, é provável que seja instável, e qualquer "
"jogo salvo que você fizer pode não funcionar em futuras versões do ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Iniciar de qualquer maneira"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "Emulador AdLib"
@@ -1658,11 +1711,11 @@ msgstr "Emulador FM Towns"
msgid "PC-98 Audio"
msgstr "Áudio"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Inicializando Emulador MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "Emulador MT-32"
@@ -1694,7 +1747,7 @@ msgstr "Você realmente deseja sair?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Sair"
@@ -1781,12 +1834,12 @@ msgstr ""
msgid "Swipe three fingers to the right to toggle."
msgstr ""
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
#, fuzzy
msgid "OpenGL"
msgstr "Abrir"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr ""
@@ -1801,19 +1854,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normal (sem escala)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Correção de proporção habilitada"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Correção de proporção desabilitada"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Ativa os filtros gráficos"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Modo janela"
@@ -1847,7 +1900,7 @@ msgid "Windows MIDI"
msgstr "MIDI Windows"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~F~echar"
@@ -2342,20 +2395,36 @@ msgstr ""
"Não se esqueça de mapear uma tecla para \"Ocultar a barra de ferramentas\" "
"para ver todo o seu inventário"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Procurar por Atualizações..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr ""
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr ""
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr ""
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2379,27 +2448,46 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules Green"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Restaurar jogo:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Restaurar"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2410,7 +2498,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2421,7 +2509,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2432,7 +2520,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Arquivo de vídeo '%s' não encontrado!"
@@ -2464,16 +2552,16 @@ msgstr ""
"Pressione OK para convertê-los agora, caso contrário você será solicitado "
"novamente na próxima vez que você iniciar o jogo.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
#, fuzzy
msgid "Use bright palette mode"
msgstr "Item da direita superior"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr ""
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr ""
@@ -2481,7 +2569,7 @@ msgstr ""
"\n"
"%s"
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr ""
@@ -2502,7 +2590,7 @@ msgstr "Modo rápido"
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Falha ao salvar o jogo"
@@ -2672,49 +2760,59 @@ msgid ""
"\n"
msgstr ""
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "Modo ~Z~ip ativado"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "Modo ~T~ransições ativado"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~S~oltar Página"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~E~xibir Mapa"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "~M~enu Principal ScummVM"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "Modo ~E~feitos de água ativado"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr ""
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2723,25 +2821,25 @@ msgstr ""
"Não é possível salvar o jogo na posição %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
#, fuzzy
msgid "Load file"
msgstr "Carregar jogo:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Carregando jogo..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
#, fuzzy
msgid "Save file"
msgstr "Falha ao salvar jogo!"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Salvando jogo..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2758,11 +2856,11 @@ msgstr ""
"Pressione OK para convertê-los agora, caso contrário você será solicitado na "
"próxima vez.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM converteu com êxito todos os seus jogos salvos."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2819,183 +2917,200 @@ msgstr ""
msgid "Use an alternative game intro (CD version only)"
msgstr ""
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr ""
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr ""
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Ligar modo Roland GS"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
#, fuzzy
msgid "Prefer digital sound effects"
msgstr "Volume dos efeitos sonoros especiais"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr ""
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
msgstr ""
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr ""
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr ""
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
#, fuzzy
msgid "Use silver cursors"
msgstr "Cursor normal"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr ""
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Insera o Disk %c e Pressione o Botão para Continuar."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Incapaz de encontrar %s, (%c%d) Pressione o Botão."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Erro de leitura do disco %c, (%c%d) Pressione o Botão."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Jogo pausado. Pressione ESPAÇO para continuar."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
#, fuzzy
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Tem certeza de que deseja reiniciar? (S/N)S"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
#, fuzzy
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Tem certeza de que deseja sair? (S/N)S"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Jogar"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Insira o disco para salvar/carregar o jogo"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Você deve digitar um nome"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "O jogo NÃO foi salvo (disco cheio?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "O jogo NÃO foi carregado"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Salvando '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Carregando '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Dê um nome ao seu SAVE"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Selecione um jogo para CARREGAR"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Título do jogo)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~A~nterior"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~P~róximo"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Somente Voz"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Voz e Legendas"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Somente Legendas"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Voz e Legendas"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr ""
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr ""
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr ""
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr ""
@@ -3532,26 +3647,26 @@ msgstr "Voar para direita"
msgid "Fly to lower right"
msgstr "Voar para direita inferior"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
#, fuzzy
msgid "Snap scroll on"
msgstr "Descer na lista"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
#, fuzzy
msgid "Music volume: "
msgstr "Volume da Música:"
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
#, fuzzy
msgid "Subtitle speed: "
msgstr "Rapidez legendas:"
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3561,7 +3676,7 @@ msgstr ""
"LucasArts,\n"
"mas %s está faltando. Utilizando AdLib ao invés."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
#, fuzzy
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
@@ -3741,12 +3856,21 @@ msgstr ""
msgid "Show labels for objects on mouse hover"
msgstr ""
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3848,9 +3972,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Filtro de imagem ativo: Nearest"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Ligar modo Roland GS"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Adicionar Jogo..."
diff --git a/po/ru_RU.po b/po/ru_RU.po
index ba91013bb5..4979c5a072 100644
--- a/po/ru_RU.po
+++ b/po/ru_RU.po
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.8.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
-"PO-Revision-Date: 2016-02-21 23:32+0300\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
+"PO-Revision-Date: 2016-05-22 17:04+0300\n"
"Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n"
"Language-Team: Russian\n"
"Language: Russian\n"
@@ -55,15 +55,16 @@ msgstr "²ÒÕàå"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "¾âÜÕÝÐ"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ßÕàÕ×ÐߨáÐâì íâÞâ äÐÙÛ?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "´Ð"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "ÁØÝãáÞØÔÐ"
msgid "Triangle"
msgstr "ÂàÕãÓÞÛìÝÐï"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "ÀÐ×ÝÞÕ"
@@ -205,14 +206,14 @@ msgstr "ÁÑàÞá"
msgid "Reset all FluidSynth settings to their default values."
msgstr "ÁÑàÞáØâì ÒáÕ ãáâÐÝÞÒÚØ FluidSynth Ò ×ÝÐçÕÝØï ßÞ ãÜÞÛçÐÝØî."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -242,15 +243,15 @@ msgstr "·ÐÚàëâì"
msgid "Mouse click"
msgstr "ºÛØÚ Üëèìî"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "¿ÞÚÐ×Ðâì ÚÛÐÒØÐâãàã"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "¿ÕàÕÝÐ×ÝÐçØâì ÚÛÐÒØèØ"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "¿ÕàÕÚÛîçÕÝØÕ ÝÐ ÒÕáì íÚàÐÝ"
@@ -325,8 +326,8 @@ msgid ""
msgstr ""
"Ï×ëÚ ØÓàë. ¸×ÜÕÝÕÝØÕ íâÞÙ ÝÐáâàÞÙÚØ ÝÕ ßàÕÒàÐâØâ ØÓàã ÝÐ ÐÝÓÛØÙáÚÞÜ Ò àãááÚãî"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<ßÞ ãÜÞÛçÐÝØî>"
@@ -348,11 +349,11 @@ msgstr "¿ÛÐâäÞàÜÐ:"
msgid "Engine"
msgstr "´ÒØÖÞÚ"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "³àÐäØÚÐ"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "³àä"
@@ -365,7 +366,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ ÓàÐäØÚØ"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "°ãÔØÞ"
@@ -378,11 +379,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ ÐãÔØÞ"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "³àÞÜÚÞáâì"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "³àÞÜÚ"
@@ -396,216 +397,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ ÓàÞÜÚÞáâØ"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "¿ÕàÕÚàëâì ÓÛÞÑÐÛìÝëÕ ãáâÐÝÞÒÚØ MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "¿ãâØ"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "¿ãâØ"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "¿ãâì Ú ØÓàÕ:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "³ÔÕ ØÓàÐ:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "´Þß. ßãâì:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "ÃÚÐ×ëÒÐÕâ ßãâì Ú ÔÞßÞÛÝØâÕÛìÝëÜ äÐÙÛÐÜ ÔÐÝÝëå ÔÛï ØÓàë"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "´Þß. ßãâì:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "ÁÞåàÐÝÕÝØï ØÓà:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "ÃÚÐ×ëÒÐÕâ ßãâì Ú áÞåàÐÝÕÝØïÜ ØÓàë"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "¿ãâì áÞåà:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "½Õ ×ÐÔÐÝ"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "¿Þ ãÜÞÛçÐÝØî"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "²ëÑÕàØâÕ SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "²ëÑÕàØâÕ ÔØàÕÚâÞàØî á äÐÙÛÐÜØ ØÓàë"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "²ëÑÕàØâÕ ÔÞßÞÛÝØâÕÛìÝãî ÔØàÕÚâÞàØî ØÓàë"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "²ëÑÕàØâÕ ÔØàÕÚâÞàØî ÔÛï áÞåàÐÝÕÝØÙ"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "ÍâÞâ ID ØÓàë ãÖÕ ØáßÞÛì×ãÕâáï. ¿ÞÖÐÛãÙáâÐ, ÒëÑÕàØâÕ ÔàãÓÞÙ."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~²~ëåÞÔ"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "·ÐÒÕàèØâì ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "¾ ß~à~ÞÓàÐÜÜÕ..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "¾ ßàÞÓàÐÜÜÕ ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~½~ÐáâàÞÙÚØ..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "¸×ÜÕÝØâì ÓÛÞÑÐÛìÝëÕ ÝÐáâàÞÙÚØ ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "¿~ã~áÚ"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "·ÐßãáâØâì ÒëÑàÐÝÝãî ØÓàã"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~·~ÐÓàãרâì..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "·ÐÓàãרâì áÞåàÝÕÝØÕ ÔÛï ÒëÑàÐÝÝÞÙ ØÓàë"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~´~ÞÑÐÒØâì ØÓàã..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "ÃÔÕàÖØÒÐÙâÕ ÚÛÐÒØèã Shift, çâÞÑë ÔÞÑÐÒØâì ÝÕáÚÞÛìÚÞ ØÓà"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "½~Ð~áâàÞÙÚØ ØÓàë..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "¸×ÜÕÝØâì ÝÐáâàÞÙÚØ ØÓàë"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~Ã~ÔÐÛØâì ØÓàã"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "ÃÔÐÛØâì ØÓàã Ø× áߨáÚÐ. ½Õ ãÔÐÛïÕâ ØÓàã á ÝÞáØâÕÛï"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~´~ÞÑ. ØÓàã..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "½~Ð~á. ØÓàë..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~Ã~ÔÐÛØâì ØÓàã"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "¿ÞØáÚ Ò áߨáÚÕ ØÓà"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "¿ÞØáÚ:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "·ÐÓàãרâì ØÓàã:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "·ÐÓàãרâì"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -613,39 +615,39 @@ msgstr ""
"²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ×ÐßãáâØâì ÔÕâÕÚâÞà ÒáÕå ØÓà? ÍâÞ ßÞâÕÝæØÐÛìÝÞ ÜÞÖÕâ "
"ÔÞÑÐÒØâì ÑÞÛìèÞÕ ÚÞÛØçÕáâÒÞ ØÓà."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕâ ÞâÚàëâì ãÚÐ×ÐÝÝãî ÔØàÕÚâÞàØî!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕâ ÝÐÙâØ ØÓàã Ò ãÚÐ×ÐÝÝÞÙ ÔØàÕÚâÞàØØ!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "²ëÑÕàØâÕ ØÓàã:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ãÔÐÛØâì ÝÐáâàÞÙÚØ ÔÛï íâÞÙ ØÓàë?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "²ë åÞâØâÕ ×ÐÓàãרâì ØÓàã?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "ÍâÐ ØÓàÐ ÝÕ ßÞÔÔÕàÖØÒÐÕâ ×ÐÓàã×Úã áÞåàÐÝÕÝØÙ çÕàÕ× ÓÛÐÒÝÞÕ ÜÕÝî."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ÝÕ áÜÞÓ ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚÐ ÒëÑàÐÝÝÞÙ ØÓàë!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "¼ÝÞÓÞ ØÓà..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "·Ðߨáì..."
@@ -688,133 +690,133 @@ msgstr "¿ÕàÕÚÛîçØâìáï Ò ØÓàã"
msgid "Fast replay"
msgstr "±ëáâàÞÕ ÒÞáßàÞØ×ÒÕÔÕÝØÕ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "½ØÚÞÓÔÐ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "ÚÐÖÔëÕ 5 ÜØÝãâ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "ÚÐÖÔëÕ 10 ÜØÝãâ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "ÚÐÖÔëÕ 15 ÜØÝãâ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "ÚÐÖÔëÕ 30 ÜØÝãâ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 Ú³æ"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "½Õ ×ÐÔÐÝ"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "½Õ ãÔÐÛÞáì ßàØÜÕÝØâì Ø×ÜÕÝÕÝØï ÝÕÚÞâÞàëå ÓàÐäØçÕáÚØå ÝÐáâàÞÕÚ:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "ÒØÔÕÞàÕÖØÜ ÝÕ ÜÞÖÕâ Ñëâì Ø×ÜÕÝñÝ."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "ßÞÛÝÞíÚàÐÝÝëÙ àÕÖØÜ ÝÕ ÜÞÖÕâ Ñëâì Ø×ÜÕÝñÝ"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "àÕÖØÜ ÚÞààÕÚâØàÞÒÚØ áÞÞâÝÞèÕÝØï áâÞàÞÝ ÝÕ ÜÞÖÕâ Ñëâì Ø×ÜÕÝñÝ"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "³àÐä. àÕÖØÜ:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "ÀÕÖØÜ àÐáâàÐ:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "ÁßÕæØÐÛìÝëÕ àÕÖØÜë àÕÝÔÕàØÝÓÐ, ßÞÔÔÕàÖØÒÐÕÜëÕ ÝÕÚÞâÞàëÜØ ØÓàÐÜØ"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "¿ÞÛÝÞíÚàÐÝÝëÙ àÕÖØÜ"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "ºÞààÕÚâØàÞÒÐâì áÞÞâÝÞèÕÝØÕ áâÞàÞÝ ÔÛï ØÓà á àÐ×àÕèÕÝØÕÜ 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "¿àÕÔßÞçØâÐÕÜÞÕ:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "·ÒãÚÞÒÞÕ ãáâ-ÒÞ:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
"ÃÚÐ×ëÒÐÕâ ßàÕÔßÞçØâÐÕÜÞÕ ×ÒãÚÞÒÞÕ ãáâàÞÙáâÒÞ ØÛØ íÜãÛïâÞà ×ÒãÚÞÒÞÙ ÚÐàâë"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "ÃÚÐ×ëÒÐÕâ ÒëåÞÔÝÞÕ ×ÒãÚÞÒÞÕ ãáâàÞÙáâÒÞ ØÛØ íÜãÛïâÞà ×ÒãÚÞÒÞÙ ÚÐàâë"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "¿àÕÔßÞçØâÐÕÜÞÕ:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "·ÒãÚÞÒÞÕ ãáâ-ÒÞ:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "ÍÜãÛïâÞà AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "·ÒãÚÞÒÐï ÚÐàâÐ AdLib ØáßÞÛì×ãÕâáï ÜÝÞÓØÜØ ØÓàÐÜØ"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "ÇÐáâÞâÐ ×ÒãÚÐ:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -822,68 +824,64 @@ msgstr ""
"±¾ÛìèØÕ ×ÝÐçÕÝØï ×ÐÔÐîâ ÛãçèÕÕ ÚÐçÕáâÒÞ ×ÒãÚÐ, ÞÔÝÐÚÞ ÞÝØ ÜÞÓãâ ÝÕ "
"ßÞÔÔÕàÖØÒÐâìáï ÒÐèÕÙ ×ÒãÚÞÒÞÙ ÚÐàâÞÙ"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "ÃáâàÞÙáâÒÞ GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "ÃÚÐ×ëÒÐÕâ ÒëåÞÔÝÞÕ ×ÒãÚÞÒÞÕ ãáâàÞÙáâÒÞ ÔÛï MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "½Õ ØáßÞÛì×ÞÒÐâì Üã×ëÚã ÔÛï General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "¸áßÞÛì×ÞÒÐâì ßÕàÒÞÕ ÔÞáâãßÝÞÕ ãáâàÞÙáâÒÞ"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont'ë ßÞÔÔÕàÖØÒÐîâáï ÝÕÚÞâÞàëÜØ ×ÒãÚÞÒëÜØ ÚÐàâÐÜØ, FluidSynth Ø "
"Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "ÁÜÕèÐÝÝëÙ àÕÖØÜ AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "¸áßÞÛì×ÞÒÐâì Ø MIDI, Ø AdLib ÔÛï ÓÕÝÕàÐæØØ ×ÒãÚÐ"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "ÃáØÛÕÝØÕ MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "½ÐáâàÞÙÚØ FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "Ãáâà. MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"ÃÚÐ×ëÒÐÕâ ×ÒãÚÞÒÞÕ ãáâàÞÙáâÒÞ ßÞ ãÜÞÛçÐÝØî ÔÛï ÒëÒÞÔÐ ÝÐ Roland MT-32/LAPC1/"
"CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "½ÐáâÞïéØÙ Roland MT-32 (×ÐßàÕâØâì íÜãÛïæØî GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -891,16 +889,16 @@ msgstr ""
"¾âÜÕâìâÕ, ÕáÛØ ã ÒÐá ßÞÔÚÛîçÕÝÞ Roland-áÞÒÜÕáâØÜÞÕ ×ÒãÚÞÒÞÕ ãáâàÞÙáâÒÞ Ø Òë "
"åÞâØâÕ ÕÓÞ ØáßÞÛì×ÞÒÐâì"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "½ÐáâÞïéØÙ Roland MT-32 (ÑÕ× íÜãÛïæØØ GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "ÃáâàÞÙáâÒÞ Roland GS (àÐ×àÕèØâì ÜÐßߨÝÓ MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -908,171 +906,187 @@ msgstr ""
"¾âÜÕâìâÕ, ÕáÛØ åÞâØâÕ àÐ×àÕèØâì ÜÐßߨÝÓ ÔÛï íÜãÛïæØØ MT-32 ÝÐ ãáâàÞÙáâÒÕ "
"Roland GS"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "½Õ ØáßÞÛì×ÞÒÐâì Üã×ëÚã ÔÛï MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "ÂÕÚáâ Ø Þ×ÒãçÚÐ:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "¾×ÒãçÚÐ"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "ÁãÑâØâàë"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "¾ÑÐ"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "ÁÚÞàÞáâì âØâàÞÒ:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "ÂÕÚáâ Ø Þ×ÒãçÚÐ:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "¾×Ò"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "狄"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "¾ÑÐ"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "¿ÞÚÐ×ëÒÐâì áãÑâØâàë Ø ÒÞáßàÞØ×ÒÞÔØâì àÕçì"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "ÁÚÞàÞáâì âØâàÞÒ:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "³àÞÜÚ. Üã×ëÚØ:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "³àÞÜÚ. Üã×ëÚØ:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "²ëÚÛ. Òáñ"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "³àÞÜÚÞáâì SFX:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "³àÞÜÚÞáâì áßÕæØÐÛìÝëå ×ÒãÚÞÒëå íääÕÚâÞÒ"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "³àÞÜÚ. SFX:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "³àÞÜÚ. Þ×ÒãçÚØ:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "³àÞÜÚ. Þ×ÒãçÚØ:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "½ÐáâàÞÙÚØ FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "¿ãâì Ú âÕÜÐÜ:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "³ÔÕ âÕÜë:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"ÃÚÐ×ëÒÐÕâ ßãâì Ú ÔÞßÞÛÝØâÕÛìÝëÜ äÐÙÛÐÜ ÔÐÝÝëå, ØáßÞÛì×ãÕÜëå ÒáÕÜØ ØÓàÐÜØ "
"ÛØÑÞ ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "¿ãâì Ú ßÛÐÓØÝÐÜ:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "¿ãâì Ú ßÛÐÓØÝÐÜ:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "ÀÐ×ÝÞÕ"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "ÂÕÜÐ:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "ÀØáÞÒÐÛÚÐ GUI:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "°ÒâÞáÞåàÐÝÕÝØÕ:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "°ÒâÞáÞåà.:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "ºÛÐÒØèØ"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "Ï×ëÚ GUI:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Ï×ëÚ ÓàÐäØçÕáÚÞÓÞ ØÝâÕàäÕÙáÐ ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "¿àÞÒÕàïâì ÞÑÝÞÒÛÕÝØï:"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "ºÐÚ çÐáâÞ ßàÞÒÕàïâì ÞÑÝÞÒÛÕÝØï ScummVM"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "¿àÞÒÕàØâì áÕÙçÐá"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "²ë ÔÞÛÖÝë ßÕàÕ×ÐßãáâØâì ScummVM, çâÞÑë ßàØÜÕÝØâì Ø×ÜÕÝÕÝØï."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "½Õ ÜÞÓã ߨáÐâì Ò ÒëÑàÐÝÝãî ÔØàÕÚâÞàØî. ¿ÞÖÐÛãÙáâÐ, ãÚÐÖØâÕ ÔàãÓãî."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "²ëÑÕàØâÕ ÔØàÕÚâÞàØî ÔÛï âÕÜ GUI"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "²ëÑÕàØâÕ ÔØàÕÚâÞàØî á ÔÞßÞÛÝØâÕÛìÝëÜØ äÐÙÛÐÜØ"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "²ëÑÕàØâÕ ÔØàÕÚâÞàØî á ßÛÐÓØÝÐÜØ"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1089,65 +1103,65 @@ msgstr "# áÛÕÔ"
msgid "add"
msgstr "ÔÞÑ"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "ÃÔÐÛØâì áØÜÒÞÛ"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Æäà"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "²ÞáßàÞØ×ÒÕáâØ ØÛØ ×ÐߨáÐâì ØÓàÞÒÞÙ ßàÞæÕáá"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "ÃÔÐÛØâì"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "·ÐߨáÐâì"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "²ÞáßàÞØ×ÒÕáâØ"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "ÀÕÔÐÚâØàÞÒÐâì"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "°ÒâÞà: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "·ÐÜÕâÚØ: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ãÔÐÛØâì íâã ×Ðߨáì?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "½ÕØ×ÒÕáâÝëÙ ÐÒâÞà"
@@ -1211,7 +1225,7 @@ msgstr "ÁÞ×ÔÐâì ÝÞÒãî ×Ðߨáì ØÓàë"
msgid "Name: "
msgstr "½Ð×ÒÐÝØÕ: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "²ÒÕÔØâÕ ÞߨáÐÝØÕ áÛÞâÐ %d:"
@@ -1220,64 +1234,88 @@ msgstr "²ÒÕÔØâÕ ÞߨáÐÝØÕ áÛÞâÐ %d:"
msgid "Select a Theme"
msgstr "²ëÑÕàØâÕ âÕÜã"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "±Õ× ÓàÐäØÚØ"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "±Õ× ÓàÐäØÚØ"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "ÁâÐÝÔÐàâÝëÙ àÐáâÕàØ×ÐâÞà"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "ÁâÐÝÔÐàâÝëÙ"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "ÀÐáâÕàØ×ÐâÞà áÞ áÓÛÐÖØÒÐÝØÕÜ"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "ÁÞ áÓÛÐÖØÒÐÝØÕÜ"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM áâÐÛ ßÞÔÔÕàÖØÒÐâì ÐÒâÞÜÐâØçÕáÚãî ßàÞÒÕàÚã\n"
+"ÞÑÝÞÒÛÕÝØÙ, ÚÞâÞàÐï âàÕÑãÕâ ÔÞáâãßÐ Ò ¸ÝâÕàÝÕâ.\n"
+"\n"
+"²ë åÞâØâÕ ÒÚÛîçØâì íâã ÞßæØî?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(²ë ÒáÕÓÔÐ ÜÞÖÕâÕ ÒÚÛîçØâì Õñ Ò ÝÐáâàÞÙÚÐå ÝÐ ×ÐÚÛÐÔÚÕ \"ÀÐ×ÝÞÕ\")"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "°ÒâÞÜÐâØçÕáÚØ ßàÞÒÕàïâì ÞÑÝÞÒÛÕÝØï"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "¿àÞÔÞÛÖØâì"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "¾çØáâØâì ×ÝÐçÕÝØÕ"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "´ÒØÖÞÚ ÝÕ ßÞÔÔÕàÖØÒÐÕâ ãàÞÒÕÝì ÞâÛÐÔÚØ '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "¼ÕÝî"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "¿àÞßãáâØâì"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "¿Ðã×Ð"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "¿àÞßãáâØâì áâàÞÚã"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "¾èØÑÚÐ ×ÐßãáÚÐ ØÓàë:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "½Õ ÜÞÓã ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚÐ ÒëÑàÐÝÝÞÙ ØÓàë"
@@ -1372,17 +1410,33 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules ÏÝâÐàÝëÙ"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "µÖÕÔÝÕÒÝÞ"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "µÖÕÝÕÔÕÛìÝÞ"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "µÖÕÜÕáïçÝÞ"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<½ÕßàÐÒØÛìÝÞÕ ×ÝÐçÕÝØÕ>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "ºÐÖÕâáï, çâÞ ØÓàÐ '%s' Õéñ ÝÕØ×ÒÕáâÝÐ."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"¿ÞÖÐÛãÙáâÐ, ßÕàÕÔÐÙâÕ áÛÕÔãîéØÕ ÔÐÝÝëÕ ÚÞÜÐÝÔÕ ScummVM ÒÜÕáâÕ á ÝÐ×ÒÐÝØÕÜ"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "ØÓàë, ÚÞâÞàãî Òë ßëâÐÕâÕáì ÔÞÑÐÒØâì, Ø ãÚÐÖØâÕ Õñ ÒÕàáØî, ï×ëÚ Ø â.Ô."
@@ -1390,11 +1444,11 @@ msgstr "ØÓàë, ÚÞâÞàãî Òë ßëâÐÕâÕáì ÔÞÑÐÒØâì, Ø ãÚÐÖØâÕ Õñ ÒÕàáØî, ï×ëÚ Ø â.Ô."
msgid "~R~esume"
msgstr "¿àÞÔÞÛ~Ö~Øâì"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~·~ÐÓàãרâì"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~·~ÐߨáÐâì"
@@ -1419,15 +1473,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~²~ ÓÛÐÒÝÞÕ ÜÕÝî"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "ÁÞåàÐÝØâì ØÓàã:"
@@ -1436,15 +1490,16 @@ msgstr "ÁÞåàÐÝØâì ØÓàã:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "ÁÞåàÐÝØâì"
@@ -1468,13 +1523,13 @@ msgstr ""
"ÑÐ×ÞÒÞÙ ØÝäÞàÜÐæØÕÙ, Ð âÐÚÖÕ ØÝáâàãÚæØïÜØ Þ âÞÜ, ÚÐÚ ßÞÛãçØâì ÔÐÛìÝÕÙèãî "
"ßÞÜÞéì."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "¾~â~ÜÕÝÐ"
@@ -1482,23 +1537,23 @@ msgstr "¾~â~ÜÕÝÐ"
msgid "~K~eys"
msgstr "~º~ÛÐÒØèØ"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "½Õ ÜÞÓã ØÝØæØÐÛØ×ØàÞÒÐâì äÞàÜÐâ æÒÕâÐ."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "½Õ ãÔÐÛÞáì ßÕàÕÚÛîçØâì ÒØÔÕÞàÕÖØÜ: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "½Õ ãÔÐÛÞáì ØáßÞÛì×ÞÒÐâì ÚÞààÕÚæØî áÞÞâÝÞèÕÝØï áâÞàÞÝ."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "½Õ ÜÞÓã ßàØÜÕÝØâì ßÞÛÝÞíÚàÐÝÝëÙ àÕÖØÜ."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1512,7 +1567,7 @@ msgstr ""
"ÝÐ ÖñáâÚØÙ ÔØáÚ. ¿ÞÔàÞÑÝÞáâØ ÜÞÖÝÞ ÝÐÙâØ Ò\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1527,7 +1582,7 @@ msgstr ""
"ßÞïÒØâáï Üã×ëÚÐ. ¿ÞÔàÞÑÝÞáâØ ÜÞÖÝÞ ÝÐÙâØ Ò\n"
"äÐÙÛÕ README."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1537,7 +1592,7 @@ msgstr ""
"README ×Ð ÑÐ×ÞÒÞÙ ØÝäÞàÜÐæØÕÙ, Ð âÐÚÖÕ ØÝáâàãÚæØïÜØ Þ âÞÜ, ÚÐÚ ßÞÛãçØâì "
"ÔÐÛìÝÕÙèãî ßÞÜÞéì."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1547,11 +1602,11 @@ msgstr ""
"ßÞÔÔÕàÖØÒÐÕâáï ScummVM ßÞÛÝÞáâìî. ¾ÝÐ, áÚÞàÕÕ ÒáÕÓÞ, ÝÕ ÑãÔÕâ àÐÑÞâÐâì "
"áâÐÑØÛìÝÞ, Ø áÞåàÐÝÕÝØï ØÓà ÜÞÓãâ ÝÕ àÐÑÞâÐâì Ò ÑãÔãéØå ÒÕàáØïå ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "²áñ àÐÒÝÞ ×ÐßãáâØâì"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "ÍÜãÛïâÞà AdLib"
@@ -1632,11 +1687,11 @@ msgstr "°ãÔØÞ FM-Towns"
msgid "PC-98 Audio"
msgstr "°ãÔØÞ PC-98"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "½ÐáâàÐØÒÐî íÜãÛïâÞà MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "ÍÜãÛïâÞà MT-32"
@@ -1668,7 +1723,7 @@ msgstr "²ë ÔÕÙáâÒØâÕÛìÝÞ åÞâØâÕ ÒëÙâØ?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "²ëåÞÔ"
@@ -1753,11 +1808,11 @@ msgstr "ÀÕÖØÜ ÐÒâÞÔàíÓÐ áÕÙçÐá"
msgid "Swipe three fingers to the right to toggle."
msgstr "¿àÞÒÕÔØâÕ âàÕÜï ßÐÛìæÐÜØ ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝØï."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (ÑÕ× äØÛìâàÞÒ)"
@@ -1772,19 +1827,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "±Õ× ãÒÕÛØçÕÝØï"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒÚÛîçÕÝÐ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "ºÞààÕÚæØï áÞÞâÝÞèÕÝØï áâÞàÞÝ ÒëÚÛîçÕÝÐ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "°ÚâØÒÝëÙ ÓàÐäØçÕáÚØÙ äØÛìâà:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "¾ÚÞÝÝëÙ àÕÖØÜ"
@@ -1817,7 +1872,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~·~ÐÚàëâì"
@@ -2307,20 +2362,38 @@ msgstr ""
"½Õ ×ÐÑãÔìâÕ ÝÐ×ÝÐçØâì ÚÛÐÒØèã ÔÛï ÔÕÙáâÒØï 'Hide Toolbar', çâÞÑë ãÒØÔÕâì "
"ÒÕáì ØÝÒÕÝâÐàì Ò ØÓàÕ"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
-msgstr "¿àÞÒÕàïî ÞÑÝÞÒÛÕÝØï..."
+msgstr "¿àÞÒÕàØâì ÞÑÝÞÒÛÕÝØï..."
+
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "ÀÕÖØÜ ÑÕ× æÒÕâÐ"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "¿ÞÚÐ×ëÒÐâì áâàÞÚã ÞÑêÕÚâÞÒ"
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "¸áßÞÛì×ÞÒÐâì ÞàØÓØÝÐÛìÝëÕ íÚàÐÝë ×ÐߨáØ/çâÕÝØï ØÓàë"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2350,27 +2423,48 @@ msgstr ""
"²ÚÛîçÐÕâ ßÞÔÔÕàÖÚã ÜëèØ. ¿Þ×ÒÞÛïÕâ ØáßÞÛì×ÞÒÐâì Üëèì ÔÛï ßÕàÕÜÕéÕÝØï Ø Ò "
"ÜÕÝî ØÓàë."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "¸áßÞÛì×ÞÒÐâì èàØäâ Hercules"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+"¸áßÞÛì×ãÕâ èàØäâ ÒëáÞÚÞÓÞ àÐ×àÕèÕÝØï Hercules, ÕáÛØ ÔÞáâãßÕÝ äÐÙÛ áÞ èàØäâÞÜ."
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "¿Ðã×Ð ÒÞ ÒàÕÜï ÒÒÞÔÐ ÚÞÜÐÝÔ"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"¿ÞÚÐ×ëÒÐÕâ ÞÚÝÞ áÞ áâàÞÚÞÙ ÒÒÞÔÐ ÚÞÜÐÝÔë Ø áâÐÒØâ ØÓàã ÝÐ ßÐã×ã (ÚÐÚ Ò SCI) "
+"ÒÜÕáâÞ ÒÒÞÔÐ Ò àÕÐÛìÝÞÜ ÒàÕÜÕÝØ."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "²ÞááâÐÝÞÒØâì ØÓàã:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "²ÞááâÐÝÞÒØâì"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2381,7 +2475,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2392,7 +2486,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2403,7 +2497,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "ÄÐÙÛ ×ÐáâÐÒÚØ '%s' ÝÕ ÝÐÙÔÕÝ!"
@@ -2434,20 +2528,20 @@ msgstr ""
"½ÐÖÜØâÕ ¾º, çâÞÑë ßÕàÕÒÕáâØ Øå Ò ÝÞÒëÙ äÞàÜÐâ áÕÙçÐá, Ò ßàÞâØÒÝÞÜ áÛãçÐÕ íâÞ "
"áÞÞÑéÕÝØÕ ßÞïÒØâáï áÝÞÒÐ ßàØ áÛÕÔãîéÕÜ ×ÐßãáÚÕ ØÓàë.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "¸áßÞÛì×ÞÒÐâì àÕÖØÜ ïàÚÞÙ ßÐÛØâàë"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "ÀØáãÕâ ÓàÐäØÚã á ØáßÞÛì×ÞÒÐÝØÕÜ ïàÚÞÙ ßÐÛØâàë ØÓàë"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "½Õ ãÔÐÛÞáì ×ÐÓàãרâì áÞåàÐÝñÝÝãî ØÓàã Ø× äÐÙÛÐ."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã Ò äÐÙÛ."
@@ -2464,7 +2558,7 @@ msgstr "ÀÕÖØÜ ãáÚÞàÕÝÝÞÓÞ ÒØÔÕÞ"
msgid "Play movies at an increased speed"
msgstr "²ÞáßàÞØ×ÒÞÔØâ ÒØÔÕÞàÞÛØÚØ á ãÒÕÛØçÕÝÝÞÙ áÚÞàÞáâìî"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "½Õ ãÔÐÛÞáì áÞåàÐÝØâì ØÓàã"
@@ -2639,49 +2733,57 @@ msgstr ""
"ÞâÚàëâì ÞâÛÐÔÞçÝãî ÚÞÝáÞÛì ScummVM Ø ÒÒÕáâØ ÚÞÜÐÝÔã 'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "¿àÞØÓàëÒÐâì àÞÛØÚ ßàÞÛñâÐ ÝÐÔ Myst"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr "ÀÞÛØÚ ßàÞÛñâÐ ÝÐÔ Myst ÝÕ ßàÞØÓàëÒÐÛáï ÞàØÓØÝÐÛìÝëÜ ÔÒØÖÚÞÜ."
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~À~ÕÖØÜ ÑëáâàÞÓÞ ßÕàÕåÞÔÐ ÐÚâØÒØàÞÒÐÝ"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "~¿~ÕàÕåÞÔë ÐÚâØÒØàÞÒÐÝë"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "~²~ëÑàÞáØâì áâàÐÝØæã"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
-msgstr "¿~Þ~ÚÐ×Ðâì ÚÐàâã"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
+msgstr "¿ÞÚÐ×Ðâì ~Ú~Ðàâã"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
-msgstr "~³~ÛÐÒÝÞÕ ÜÕÝî"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
+msgstr "³ÛÐÒÝÞÕ ÜÕÝ~î~"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~Í~ääÕÚâë ÒÞÔë ÒÚÛîçÕÝë"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "¿àÞßãáâØâì áæÕÝë Ø× ³ÐÛÕàÕØ ¸áâÞàØØ"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "¿Þ×ÒÞÛïÕâ ØÓàÞÚã ßàÞßãáâØâì ÒáÕ áæÕÝë Ò ³ÐÛÕàÕÕ ¸áâÞàØØ"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "ÀÐáâïÝãâì ÝÐ ÒÕáì íÚàÐÝ ÒØÔÕÞ Þ áÞ×ÔÐÝØØ ØÓàë"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "ÀÐáâïÓØÒÐÕâ ÒØÔÕÞ Þ áÞ×ÔÐÝØØ ØÓàë âÐÚ, çâÞ ÞÝÞ ×ÐÝØÜÐÕâ ÒÕáì íÚàÐÝ"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2690,23 +2792,23 @@ msgstr ""
"½Õ ÜÞÓã áÞåàÐÝØâì ØÓàã Ò ßÞרæØî %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "·ÐÓàãרâì äÐÙÛ"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "·ÐÓàãÖÐî ØÓàã..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "ÁÞåàÐÝØâì äÐÙÛ"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "ÁÞåàÐÝïî ØÓàã..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2723,11 +2825,11 @@ msgstr ""
"½ÐÖÜØâÕ ¾º, çâÞÑë ßÕàÕØÜÕÝÞÒÐâì Øå áÕÙçÐá, Ò ßàÞâØÒÝÞÜ áÛãçÐÕ íâÞ ÖÕ "
"áÞÞÑéÕÝØÕ ßÞïÒØâáï ßàØ áÛÕÔãîéÕÜ ×ÐßãáÚÕ ØÓàë.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM ãáßÕèÝÞ ßàÕÞÑàÐ×ÞÒÐÛ ÒáÕ ÒÐèØ áÞåàÐÝÕÝØï ØÓà."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2783,38 +2885,46 @@ msgstr "°ÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ"
msgid "Use an alternative game intro (CD version only)"
msgstr "¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝÞÕ ÒáâãßÛÕÝØÕ (âÞÛìÚÞ ÔÛï CD-ÒÕàáØØ ØÓàë)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "½Õ ÔÕÛÐâì ÐßßàÞÚáØÜÐæØî æÒÕâÞÒ EGA (ßÞÛÝÞæÒÕâÝëÕ äÞÝë)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"¿àÞßãáÚÐÕâ ßàÞåÞÔ ÐßßàÞÚáØÜÐæØØ æÒÕâÞÒ EGA, ÓàÐäØÚÐ ÑãÔÕâ ßÞÚÐ×ÐÝÐ áÞ ÒáÕÜØ "
"æÒÕâÐÜØ"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "²ÚÛîçØâì ÞâÞÑàÐÖÕÝØÕ ÓàÐäØÚØ ÒëáÞÚÞÓÞ àÐ×àÕèÕÝØï"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "²ÚÛîçØâì ÓàÐäØÚã Ø ÚÞÝâÕÝâ ÒëáÞÚÞÓÞ àÐàÕèÕÝØï"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr ""
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "¿àÕÔßÞçØâÐâì æØäàÞÒëÕ ×ÒãÚÞÒëÕ íääÕÚâë"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
"¾âÔÐÒÐâì ßàÕÔßÞçâÕÝØÕ æØäàÞÒëÜ ×ÒãÚÞÒëÜ íääÕÚâÐÜ ÒÜÕáâÞ áØÝâÕרàÞÒÐÝÝëå"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "¸áßÞÛì×ÞÒÐâì IMF/Yamaha FB-01 ÔÛï ÒëÒÞÔÐ MIDI"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2822,150 +2932,158 @@ msgstr ""
"¸áßÞÛì×ÞÒÐâì ×ÒãÚÞÒãî ÚÐàâã IBM Music Feature ØÛØ ÜÞÔãÛì áØÝâÕ×Ð Yamaha "
"FB-01 FM ÔÛï MIDI"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "¸áßÞÛì×ÞÒÐâì CD-ÐãÔØÞ"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
"¸áßÞÛì×ÞÒÐâì ×ÒãÚÞÒëÕ ÔÞàÞÖÚØ á CD ÒÜÕáâÞ Üã×ëÚØ Ø× äÐÙÛÞÒ ØÓàë (ÕáÛØ "
"ÔÞáâãßÝÞ)"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "¸áßÞÛì×ÞÒÐâì ÚãàáÞàë Windows"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"¸áßÞÛì×ÞÒÐâì ÚãàáÞàë Windows (ÜÕÝìèØÕ ßÞ àÐ×ÜÕàã Ø ÞÔÝÞæÒÕâÝëÕ) ÒÜÕáâÞ "
"ÚãàáÞàÞÒ DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "¸áßÞÛì×ÞÒÐâì áÕàÕÑàïÝëÕ ÚãàáÞàë"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"¸áßÞÛì×ÞÒÐâì ÐÛìâÕàÝÐâØÒÝëÙ ÝÐÑÞà áÕàÕÑàïÝëå ÚãàáÞàÞÒ ÒÜÕáâÞ ÞÑëçÝëå ×ÞÛÞâëå"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "¿ÞÚÐ×ëÒÐâì áâàÞÚã ÞÑêÕÚâÞÒ"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "¿ÞÚÐ×ëÒÐâì ÝÐ×ÒÐÝØï ÞÑêÕÚâÞÒ ÒÝØ×ã íÚàÐÝÐ"
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "²áâÐÒìâÕ ÔØáÚ %c Ø ÝÐÖÜØâÕ ÚÛÐÒØèã, çâÞÑë ßàÞÔÞÛÖØâì."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "½Õ ãÔÐÛÞáì ÝÐÙâØ %s, (%c%d) ½ÐÖÜØâÕ ÚÛÐÒØèã."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "¾èØÑÚÐ çâÕÝØï ÔØáÚÐ %c, (%c%d) ½ÐÖÜØâÕ ÚÛÐÒØèã."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "¸ÓàÐ ÞáâÐÝÞÒÛÕÝÐ. ½ÐÖÜØâÕ ßàÞÑÕÛ, çâÞÑë ßàÞÔÞÛÖØâì."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "²ë ãÒÕàÕÝë, çâÞ åÞâØâÕ ÝÐçÐâì áÝÞÒÐ? (Y/N)Y"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "²ë ãÒÕàÕÝë, çâÞ åÞâØâÕ ÒëÙâØ? (Y/N)Y"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "¸ÓàÐâì"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "²áâÐÒìâÕ ÔØáÚ á áÞåàÐÝÕÝØïÜØ"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "²ë ÔÞÛÖÝë ÒÒÕáâØ ØÜï"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "¸ÓàÐ ½µ ±Ë»° ×ÐߨáÐÝÐ (ÔØáÚ ßÞÛÞÝ?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "¸ÓàÐ ½µ ±Ë»° ×ÐÓàãÖÕÝÐ"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "ÁÞåàÐÝïî '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "·ÐÓàãÖÐî '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "½Ð×ÞÒØâÕ áÞåàÐÝÕÝØÕ ØÓàë"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "²ëÑÕàØâÕ ØÓàã ÔÛï ×ÐÓàã×ÚØ"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "½Ð×ÒÐÝØÕ ØÓàë)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~¿~àÕÔ"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~Á~ÛÕÔ"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "ÂÞÛìÚÞ Þ×ÒãçÚÐ"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "¾×ÒãçÚÐ Ø áãÑâØâàë"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "ÂÞÛìÚÞ áãÑâØâàë"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "¾×ÒãçÚÐ Ø âÕÚáâ"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "²ëÑÕàØâÕ ãàÞÒÕÝì áÛÞÖÝÞáâØ."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "·Ð ßÞÜÞéìî ÞÑàÐâØâÕáì Ú ØÝáâàã򾯯 Loom(TM)."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "¿àÐÚâØÚÐÝâ"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "ÍÚáßÕàâ"
@@ -3502,23 +3620,23 @@ msgstr "»ÕâÕâì ÒßàÐÒÞ"
msgid "Fly to lower right"
msgstr "»ÕâÕâì ÒßàÐÒÞ-ÒÝØ×"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒÚÛîçÕÝÐ"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "¿àÞÚàãâÚÐ áÚÐçÚÐÜØ ÒëÚÛîçÕÝÐ"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "³àÞÜÚ. Üã×ëÚØ: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "ÁÚÞàÞáâì âØâàÞÒ: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3527,7 +3645,7 @@ msgstr ""
"ÀÕÖØÜ \"àÞÔÝÞÓÞ\" MIDI âàÕÑãÕâ ÞÑÝÞÒÛÕÝØÕ Roland Upgrade Þâ\n"
"LucasArts, ÝÞ ÝÕ åÒÐâÐÕâ %s. ¿ÕàÕÚÛîçÐîáì ÝÐ AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3708,13 +3826,24 @@ msgstr "¿ÞÚÐ×ëÒÐâì ÝÐ×ÒÐÝØï ÞÑêÕÚâÞÒ"
msgid "Show labels for objects on mouse hover"
msgstr "¿ÞÚÐ×ëÒÐÕâ ÝÐ×ÒÐÝØï ÞÑêÕÚâÞÒ ßàØ ÝÐÒÕÔÕÝØØ ÚãàáÞàÐ ÜëèØ"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "¸áßÞÛì×ÞÒÐâì ÐÝÓÛØÙáÚãî Þ×ÒãçÚã"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+"¸áßÞÛì×ÞÒÐâì ÐÝÓÛØÙáÚãî Þ×ÒãçÚã ÒÜÕáâÞ ÝÕÜÕæÚÞÙ ÔÛï ÒáÕå ï×ëÚÞÒ, ÚàÞÜÕ "
+"ÝÕÜÕæÚÞÓÞ"
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"à ÒÐá ÞâáãâáâÒãÕâ äÐÙÛ 'teenagent.dat'. ÁÚÐçÐÙâÕ ÕÓÞ á ÒÕÑ-áÐÙâÐ ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3769,70 +3898,3 @@ msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
msgstr ""
"¸áßÞÛì×ÞÒÐâì MPEG-ÒØÔÕÞ Ø× DVD-ÒÕàáØØ ÒÜÕáâÞ ÒØÔÕÞ ÝØ×ÚÞÓÞ àÐ×àÕèÕÝØï Ò "
"äÞàÜÐâÕ AVI"
-
-#~ msgid "EGA undithering"
-#~ msgstr "EGA ÑÕ× àÐáâàÐ"
-
-#~ msgid "Enable undithering in EGA games"
-#~ msgstr "²ÚÛîçÐÕâ àÕÖØÜ ÑÕ× àÐáâàØàÞÒÐÝØï Ò EGA ØÓàÐå"
-
-#~ msgid "MPEG-2 cutscenes found but ScummVM has been built without MPEG-2"
-#~ msgstr ""
-#~ "½ÐÙÔÕÝë ×ÐáâÐÒÚØ Ò äÞàÜÐâÕ MPEG-2, ÝÞ ScummVM ÑëÛ áÞÑàÐÝ ÑÕ× ßÞÔÔÕàÖÚØ "
-#~ "MPEG-2"
-
-#~ msgctxt "lowres"
-#~ msgid "Mass Add..."
-#~ msgstr "¼ÝÞÓÞ ØÓà..."
-
-#~ msgid ""
-#~ "Turns off General MIDI mapping for games with Roland MT-32 soundtrack"
-#~ msgstr ""
-#~ "²ëÚÛîçÐÕâ áÞßÞáâÐÒÛÕÝØÕ General MIDI ÔÛï ØÓà á ×ÒãÚÞÒÞÙ ÔÞàÞÖÚÞÙ ÔÛï "
-#~ "Roland MT-32"
-
-#~ msgid "Standard (16bpp)"
-#~ msgstr "ÁâÐÝÔÐàâÝëÙ àÐáâÕàØ×ÐâÞà (16bpp)"
-
-#~ msgid "MPEG2 cutscenes are no longer supported"
-#~ msgstr "·ÐáâÐÒÚØ Ò äÞàÜÐâÕ MPEG2 ÑÞÛìèÕ ÝÕ ßÞÔÔÕàÖØÒÐîâáï"
-
-#~ msgid "OpenGL Normal"
-#~ msgstr "OpenGL ÑÕ× ãÒÕÛØçÕÝØï"
-
-#~ msgid "OpenGL Conserve"
-#~ msgstr "OpenGL á áÞåàÐÝÕÝØÕÜ"
-
-#~ msgid "OpenGL Original"
-#~ msgstr "OpenGL Ø×ÝÐçÐÛìÝëÙ"
-
-#~ msgid "Current display mode"
-#~ msgstr "ÂÕÚãéØÙ ÒØÔÕÞàÕÖØÜ"
-
-#~ msgid "Current scale"
-#~ msgstr "ÂÕÚãéØÙ ÜÐáèâÐÑ"
-
-#~ msgid "Active filter mode: Linear"
-#~ msgstr "°ÚâØÒÝëÙ àÕÖØÜ äØÛìâàÐ: »ØÝÕÙÝëÙ"
-
-#~ msgid "Active filter mode: Nearest"
-#~ msgstr "°ÚâØÒÝëÙ àÕÖØÜ äØÛìâàÐ: ±ÛØÖÐÙèØÙ"
-
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "²ÚÛîçØâì àÕÖØÜ Roland GS"
-
-#~ msgctxt "lowres"
-#~ msgid "Add Game..."
-#~ msgstr "´ÞÑ. ØÓàã"
-
-#~ msgid "Add Game..."
-#~ msgstr "´ÞÑÐÒØâì ØÓàã..."
-
-#~ msgid "Discovered %d new games."
-#~ msgstr "½ÐÙÔÕÝÞ %d ÝÞÒëå ØÓà."
-
-#~ msgid "Command line argument not processed"
-#~ msgstr "¿ÐàÐÜÕâàë ÚÞÜÐÝÔÝÞÙ áâàÞÚØ ÝÕ ÞÑàÐÑÞâÐÝë"
-
-#~ msgid "Invalid Path"
-#~ msgstr "½ÕÒÕàÝëÙ ßãâì"
diff --git a/po/scummvm.pot b/po/scummvm.pot
index 1edbe00e20..3a52afdde7 100644
--- a/po/scummvm.pot
+++ b/po/scummvm.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.9.0git\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -53,15 +53,16 @@ msgstr ""
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr ""
@@ -100,7 +101,7 @@ msgid "Do you really want to overwrite the file?"
msgstr ""
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -110,7 +111,7 @@ msgid "Yes"
msgstr ""
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -171,7 +172,7 @@ msgstr ""
msgid "Triangle"
msgstr ""
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr ""
@@ -203,14 +204,14 @@ msgstr ""
msgid "Reset all FluidSynth settings to their default values."
msgstr ""
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -238,15 +239,15 @@ msgstr ""
msgid "Mouse click"
msgstr ""
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr ""
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr ""
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr ""
@@ -318,8 +319,8 @@ msgid ""
"English"
msgstr ""
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr ""
@@ -341,11 +342,11 @@ msgstr ""
msgid "Engine"
msgstr ""
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr ""
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr ""
@@ -358,7 +359,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr ""
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr ""
@@ -371,11 +372,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr ""
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr ""
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr ""
@@ -389,254 +390,255 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr ""
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr ""
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr ""
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr ""
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr ""
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr ""
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr ""
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr ""
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr ""
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr ""
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr ""
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr ""
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr ""
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr ""
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr ""
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr ""
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr ""
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr ""
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr ""
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr ""
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr ""
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr ""
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr ""
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr ""
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr ""
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr ""
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr ""
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr ""
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr ""
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr ""
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr ""
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr ""
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr ""
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr ""
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr ""
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr ""
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr ""
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr ""
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr ""
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr ""
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr ""
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr ""
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr ""
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr ""
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr ""
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr ""
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr ""
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
msgstr ""
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr ""
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr ""
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr ""
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr ""
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr ""
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr ""
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr ""
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr ""
@@ -679,378 +681,390 @@ msgstr ""
msgid "Fast replay"
msgstr ""
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr ""
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr ""
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr ""
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr ""
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr ""
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr ""
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr ""
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr ""
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr ""
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr ""
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr ""
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr ""
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr ""
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr ""
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr ""
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr ""
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr ""
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr ""
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr ""
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr ""
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr ""
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr ""
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr ""
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr ""
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr ""
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr ""
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr ""
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr ""
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr ""
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr ""
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
msgstr ""
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr ""
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr ""
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr ""
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr ""
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr ""
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr ""
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr ""
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr ""
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr ""
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr ""
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr ""
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr ""
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
msgstr ""
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr ""
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr ""
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
msgstr ""
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr ""
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr ""
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr ""
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr ""
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr ""
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr ""
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr ""
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr ""
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr ""
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr ""
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr ""
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr ""
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr ""
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr ""
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr ""
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr ""
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr ""
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr ""
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr ""
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr ""
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr ""
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr ""
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr ""
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr ""
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr ""
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr ""
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr ""
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr ""
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr ""
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr ""
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr ""
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr ""
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr ""
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr ""
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr ""
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr ""
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr ""
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1065,65 +1079,65 @@ msgstr ""
msgid "add"
msgstr ""
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr ""
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr ""
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr ""
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr ""
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr ""
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr ""
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr ""
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr ""
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr ""
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr ""
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr ""
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr ""
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr ""
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr ""
@@ -1187,7 +1201,7 @@ msgstr ""
msgid "Name: "
msgstr ""
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr ""
@@ -1196,64 +1210,84 @@ msgstr ""
msgid "Select a Theme"
msgstr ""
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr ""
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr ""
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr ""
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr ""
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr ""
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr ""
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr ""
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr ""
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr ""
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr ""
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr ""
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr ""
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr ""
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr ""
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr ""
@@ -1348,16 +1382,32 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr ""
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr ""
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr ""
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr ""
@@ -1365,11 +1415,11 @@ msgstr ""
msgid "~R~esume"
msgstr ""
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr ""
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr ""
@@ -1394,15 +1444,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr ""
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr ""
@@ -1411,15 +1461,16 @@ msgstr ""
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr ""
@@ -1437,13 +1488,13 @@ msgid ""
"and for instructions on how to obtain further assistance."
msgstr ""
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr ""
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr ""
@@ -1451,23 +1502,23 @@ msgstr ""
msgid "~K~eys"
msgstr ""
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr ""
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr ""
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr ""
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr ""
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1476,7 +1527,7 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1485,25 +1536,25 @@ msgid ""
"See the README file for details."
msgstr ""
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
"and for instructions on how to obtain further assistance."
msgstr ""
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
"not work in future versions of ScummVM."
msgstr ""
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr ""
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr ""
@@ -1576,11 +1627,11 @@ msgstr ""
msgid "PC-98 Audio"
msgstr ""
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr ""
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr ""
@@ -1612,7 +1663,7 @@ msgstr ""
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr ""
@@ -1697,11 +1748,11 @@ msgstr ""
msgid "Swipe three fingers to the right to toggle."
msgstr ""
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr ""
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr ""
@@ -1716,19 +1767,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr ""
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr ""
@@ -1761,7 +1812,7 @@ msgid "Windows MIDI"
msgstr ""
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr ""
@@ -2249,20 +2300,36 @@ msgid ""
"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory"
msgstr ""
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr ""
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+msgid "Color mode"
+msgstr ""
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+msgid "Show scanlines"
+msgstr ""
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr ""
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2286,27 +2353,45 @@ msgid ""
"Enables mouse support. Allows to use mouse for movement and in game menus."
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr ""
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr ""
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr ""
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2314,7 +2399,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2322,7 +2407,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2330,7 +2415,7 @@ msgid ""
"%s"
msgstr ""
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr ""
@@ -2354,20 +2439,20 @@ msgid ""
"time you start the game.\n"
msgstr ""
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr ""
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr ""
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr ""
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr ""
@@ -2384,7 +2469,7 @@ msgstr ""
msgid "Play movies at an increased speed"
msgstr ""
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr ""
@@ -2540,72 +2625,80 @@ msgid ""
"\n"
msgstr ""
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr ""
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr ""
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr ""
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
msgstr ""
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
msgstr ""
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr ""
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr ""
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr ""
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr ""
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
"\n"
msgstr ""
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr ""
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr ""
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr ""
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr ""
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2615,11 +2708,11 @@ msgid ""
"Press OK to convert them now, otherwise you will be asked next time.\n"
msgstr ""
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr ""
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2671,179 +2764,195 @@ msgstr ""
msgid "Use an alternative game intro (CD version only)"
msgstr ""
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr ""
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr ""
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr ""
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr ""
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr ""
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr ""
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr ""
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
msgstr ""
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr ""
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr ""
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr ""
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr ""
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr ""
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr ""
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr ""
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr ""
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr ""
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr ""
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr ""
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr ""
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr ""
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr ""
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr ""
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr ""
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr ""
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr ""
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr ""
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr ""
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr ""
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr ""
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr ""
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr ""
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr ""
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr ""
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr ""
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr ""
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr ""
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr ""
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr ""
@@ -3380,30 +3489,30 @@ msgstr ""
msgid "Fly to lower right"
msgstr ""
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr ""
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr ""
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr ""
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr ""
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
"but %s is missing. Using AdLib instead."
msgstr ""
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3556,12 +3665,21 @@ msgstr ""
msgid "Show labels for objects on mouse hover"
msgstr ""
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
diff --git a/po/sv_SE.po b/po/sv_SE.po
index 82357b4dc2..8137176bc3 100644
--- a/po/sv_SE.po
+++ b/po/sv_SE.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.5.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2016-02-25 23:06+0100\n"
"Last-Translator: Hampus Flink <hampus.flink@gmail.com>\n"
"Language-Team: \n"
@@ -55,15 +55,16 @@ msgstr "Uppåt"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "Avbryt"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "Vill du verkligen skriva över filen?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "Ja"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "Sinus"
msgid "Triangle"
msgstr "Triangel"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Diverse"
@@ -206,14 +207,14 @@ msgid "Reset all FluidSynth settings to their default values."
msgstr ""
"Återställ alla FluidSynth-inställningar till deras ursprungliga värden."
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -243,15 +244,15 @@ msgstr "Stäng"
msgid "Mouse click"
msgstr "Musklick"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "Visa tangentbord"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "Ställ in tangenter"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "Fullskärmsläge"
@@ -327,8 +328,8 @@ msgstr ""
"Spelets språk. Den här inställningen omvandlar inte din spanska spelversion "
"till en engelsk"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<standard>"
@@ -350,11 +351,11 @@ msgstr "Plattform:"
msgid "Engine"
msgstr "Motor"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "Grafik"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "GFX"
@@ -367,7 +368,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "Överskrid globala grafikinställningar"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "Ljud"
@@ -380,11 +381,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "Överskrid globala ljudinställningar"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "Volym"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "Volym"
@@ -398,216 +399,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "Överskrid globala volyminställningar"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "Överskrid globala MIDI-inställningar"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "Överskrid globala MIDI-inställningar"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "Överskrid globala MT-32 inställningar"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "Överskrid globala MT-32 inställningar"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "Sökvägar"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "Sökvägar"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "Sökv. spel:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "Sökv. spel:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "Sökv. extra:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "Bestämmer sökvägen till ytterligare data som spelet använder"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "Sökv. extra:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "Sökv. sparat:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "Bestämmer var dina spardata lagras"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "Sökv. sparat:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "Ingen"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "Standard"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "Välj SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "Välj katalog med speldata"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "Välj en ytterligare spelkatalog"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "Välj katalog för spardata"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "Detta ID-namn är upptaget. Var god välj ett annat."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~A~vsluta"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "Avsluta ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "O~m~..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "Om ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~I~nställningar..."
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "Redigera globala ScummVM-inställningar"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "~S~tarta"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "Starta det valda spelet"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~L~adda..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "Ladda spardata för det valda spelet"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "Lä~g~g till spel..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "Håll ned Skift för masstillägg"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "R~e~digera spel..."
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "Redigera spelinställningarna"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~R~adera spel"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "Radera spelet från listan. Spelets datafiler påverkas inte."
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "Lä~g~g till spel..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "R~e~digera spel..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~R~adera spel"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "Sök i spellistan"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "Sök:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "Ladda spel:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "Ladda"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -615,40 +617,40 @@ msgstr ""
"Vill du verkligen använda mass-speldetektorn? Processen kan potentiellt "
"lägga till ett enormt antal spel."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM kunde inte öppna den valda katalogen!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM kunde inte hitta några spel i den valda katalogen!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "Välj spel:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "Vill du verkligen radera den här spelkonfigurationen?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "Vill du ladda sparat spel?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Det här spelet stöder inte laddning av spardata från launchern."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr ""
"ScummVM kunde inte hitta en motor kapabel till att köra det valda spelet!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "Masstillägg..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "Spela in..."
@@ -691,132 +693,132 @@ msgstr "Växla till spelet"
msgid "Fast replay"
msgstr "Snabb uppspelning"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "Aldrig"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "var 5:e minut"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "var 10:e minut"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "var 15:e minut"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "var 30:e minut"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 kHz"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 kHz"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "Ingen"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "Kunde inte verkställa några av grafikinställningarna:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "videoläget kunde inte ändras."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "fullskärmsinställningen kunde inte ändras."
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "inställningen för bildförhållandet kunde inte ändras."
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "Grafikläge:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "Renderingsläge:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "Speciella gitterlägen stödda av vissa spel"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "Fullskärmsläge"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "Korrektion av bildförhållande"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "Korrigerar bildförhållanden för 320x200-spel"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "Föredragen enhet:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "Musikenhet:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "Bestämmer din föredragna emulator för ljudenhet eller ljudkort"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "Bestämmer emulator för ljudenhet eller ljudkort"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "Föredr. enhet:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "Musikenhet:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "AdLib-emulator:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "AdLib används för musik i många spel"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "Ljudfrekvens:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -824,65 +826,61 @@ msgstr ""
"Ett högre värde betecknar bättre ljudkvalitet men stöds kanske inte av ditt "
"ljudkort"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "GM-enhet:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "Bestämmer standardenheten för General MIDI-uppspelning"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "Använd inte General MIDI-musik"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "Använd första tillgängliga enhet"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr "SoundFont stöds endast av vissa ljudkort, FluidSynth och Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "Blandat AdLib/MIDI-läge"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "Använd både MIDI och AdLib för ljudgeneration"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "MIDI gain:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "FluidSynth inställningar"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "MT-32 enhet:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"Bestämmer standardenheten för Roland MT-32/LAPC1/CM32I/CM64-uppspelning"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "Äkta Roland MT-32 (inaktivera GM-emulation)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -890,16 +888,16 @@ msgstr ""
"Aktivera om du vill använda din verkliga Roland-kompatibla och dator-"
"anslutna ljudenhet"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "Äkta Roland MT-32 (ingen GM-emulation)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "Roland GS-enhet (aktivera MT-32 mappings)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -907,171 +905,187 @@ msgstr ""
"Aktivera om du vill använda patch mapping för att emulera en MT-32 på en "
"Roland GS-enhet"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "Använd inte Roland MT-32 musik"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "Undertext och tal:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "Tal"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "Undertexter"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "Båda"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "Texthastighet:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "Text och tal:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "Tal"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "Text"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "Båda"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "Visa undertexter och spela upp tal"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "Texthastighet:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "Musikvolym:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "Musikvolym:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "Ljud av"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "SFX-volym:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "Volym för specialeffekter"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "SFX-volym:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "Talvolym:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "Talvolym:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth inställningar"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "Sökv. tema:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "Sökv. tema:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"Bestämmer sökväg till andra data som används av alla spel eller ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "Sökv. tillägg:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "Sökv. tillägg:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Diverse"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "Tema:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "GUI-rendering:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "Autospara:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "Autospara:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "Tangenter"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "GUI-språk:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "Språk för ScummVM:s användargränssnitt"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "Du måste starta om ScummVM för att ändringarna ska få effekt."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr ""
"Det går inte att skriva till den valda katalogen. Var god välj en annan."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "Välj katalog för GUI-teman"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "Välj katalog för extra filer"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "Välj katalog för tillägg"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1088,65 +1102,65 @@ msgstr "# nästa"
msgid "add"
msgstr "Lägg till"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "Radera tecken"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* Pre."
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* 123"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* ABC"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "Inspelare eller återuppspelning"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "Radera"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "Spela in"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "Spela upp"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "Redigera"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "Skapare: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "Anteckningar: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "Vill du verkligen radera den här inspelningen?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "Okänd skapare"
@@ -1210,7 +1224,7 @@ msgstr "Skapa ett nytt sparat spel"
msgid "Name: "
msgstr "Namn:"
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "Ange en beskrivning för position %d:"
@@ -1219,64 +1233,85 @@ msgstr "Ange en beskrivning för position %d:"
msgid "Select a Theme"
msgstr "Välj ett tema"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "Inaktiverad GFX"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "Inaktiverad GFX"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "Standard rendering"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "Standard"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "Antialiserad rendering"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "Antialiserad"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Sök efter uppdateringar..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "Töm sökfältet"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "Motorn stöder inte debug-nivå '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "Meny"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "Skippa"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "Paus"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "Skippa rad"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "Fel under körning av spel:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "Kunde inte hitta en motor kapabel till att köra det valda spelet"
@@ -1371,17 +1406,34 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Herkules bärnsten"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Töm sökfältet"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "Spelet i '%s' verkar vara okänt."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr ""
"Var god rapportera följande data till ScummVM-teamet tillsammans med namnet"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "på spelet du försökte lägga till och dess version/språk/etc.:"
@@ -1389,11 +1441,11 @@ msgstr "på spelet du försökte lägga till och dess version/språk/etc.:"
msgid "~R~esume"
msgstr "~F~ortsätt"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~L~adda"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~S~para"
@@ -1418,15 +1470,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "Åte~r~vänd till launcher"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "Spara spelet:"
@@ -1435,15 +1487,16 @@ msgstr "Spara spelet:"
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "Spara"
@@ -1466,13 +1519,13 @@ msgstr ""
"Kunde inte spara data (%s)! Var god läs README-filen för grundläggande "
"information och instruktioner för hur du kan få mer hjälp."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "A~v~bryt"
@@ -1480,23 +1533,23 @@ msgstr "A~v~bryt"
msgid "~K~eys"
msgstr "~T~angenter"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "Kunde inte initialisera färgformat."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "Kunde inte byta till videoläget: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "Kunde inte ändra inställningen för bildförhållanden."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "Kunde inte applicera fullskärmsinställning."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1510,7 +1563,7 @@ msgstr ""
"datafilerna till din hårddisk istället.\n"
"Se README-filen för detaljer."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1524,7 +1577,7 @@ msgstr ""
"för att kunna lyssna på spelets musik.\n"
"Se README-filen för detaljer."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1533,7 +1586,7 @@ msgstr ""
"Kunde inte ladda spardata (%s)! Hänvisa till README-filen för grundläggande "
"information och instruktioner för ytterligare assistans."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1543,11 +1596,11 @@ msgstr ""
"ScummVM. Därför är det troligtvis instabilt och om du skapar spardata kan de "
"möjligtvis vara inkompatibla med framtida versioner av ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "Starta ändå"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "AdLib-emulator"
@@ -1628,11 +1681,11 @@ msgstr "FM Towns-ljud"
msgid "PC-98 Audio"
msgstr "PC-98 ljud"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "Initialiserar MT-32 emulator"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "MT-32 emulator"
@@ -1664,7 +1717,7 @@ msgstr "Vill du verkligen avsluta?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "Avsluta"
@@ -1749,11 +1802,11 @@ msgstr "Automatiskt dragläge "
msgid "Swipe three fingers to the right to toggle."
msgstr "Svep åt höger med tre fingrar för att byta läge."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (ingen filtrering)"
@@ -1768,19 +1821,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "Normalt (ingen skalning)"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "Korrektion av bildförhållande på"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "Korrektion av bildförhållande av"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "Aktivt grafikfilter:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "Fönsterläge"
@@ -1813,7 +1866,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~S~täng"
@@ -2306,20 +2359,38 @@ msgstr ""
"Glöm inte att välja en tangent för \"Göm verktygsrad\" för att se hela "
"inventariet"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
msgstr "Sök efter uppdateringar..."
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Färgblint läge"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Visa etiketter"
+
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "Använd originalskärmar för spara/ladda"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr "Använder originalskärmarna för spara/ladda istället för ScummVM:s"
@@ -2347,27 +2418,46 @@ msgstr ""
"Aktiverar musstöd. Möjliggör användning av musen för rörelser och i "
"spelmenyer."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Herkules grön"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "Återställ spel:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "Återställ"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2378,7 +2468,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2389,7 +2479,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2400,7 +2490,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "Filmscensfilen '%s' hittades ej!"
@@ -2431,20 +2521,20 @@ msgstr ""
"Tryck på OK för att konvertera dem nu, annars kommer du tillfrågas igen "
"nästa gång du startar spelet.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "Använd ljus palett-läge"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "Visa grafik med spelets ljusa palett"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "Kunde inte läsa spardata från filen"
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "Kunde inte skriva spardata till filen."
@@ -2461,7 +2551,7 @@ msgstr "Snabb filmhastighet"
msgid "Play movies at an increased speed"
msgstr "Spela filmer i högre hastighet"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "Kunde inte spara spelet."
@@ -2636,49 +2726,59 @@ msgstr ""
"och använda kommandot 'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "~Z~ipläge aktiverat"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "Öv~e~rgångar aktiverade"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "Släpp si~d~a"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
msgstr "~V~isa karta"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
msgstr "Huvud~m~eny"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "~V~atteneffekt aktiverad"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "Skippa Hall of Records storyboard-scenerna"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "Låter spelaren skippa Hall of Records storyboard-scenerna"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "Skala dokumentärvideor till helskärm"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "Skala dokumentärvideorna så att de använder hela skärmen"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2687,25 +2787,25 @@ msgstr ""
"Kan inte spara data i position %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
#, fuzzy
msgid "Load file"
msgstr "Ladda spel:"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "Laddar speldata..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
#, fuzzy
msgid "Save file"
msgstr "Spara spelet:"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "Sparar speldata..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2722,11 +2822,11 @@ msgstr ""
"Tryck \"OK\" för att konvertera dem nu, annars kommer du tillfrågas igen "
"nästa gång du startar spelet.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM lyckades konvertera alla dina spardata."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2782,35 +2882,44 @@ msgstr "Alternativt intro"
msgid "Use an alternative game intro (CD version only)"
msgstr "Använd alternativt spelintro (endast CD-version)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "Skippa EGA-gitterpass (bakgrunder i full färg)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr "Skippa gitterpass i EGA-spel. Grafik visas i full färg."
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "Aktivera högupplöst grafik"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "Aktivera högupplöst grafik/innehåll"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+#, fuzzy
+msgid "Enable black-lined video"
+msgstr "Aktivera Roland GS-läge"
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "Föredra digitala ljudeffekter"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "Föredra digitala ljudeffekter istället för syntetiserade"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "Använd IMF/Yamaha FB-01 för MIDI-uppspelning"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2818,147 +2927,156 @@ msgstr ""
"Använd ett IMB Music Feature-kort eller en Yamaha FB-01 FM synthmodul för "
"MIDI-uppspelning"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "Använd CD-ljud"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "Använd CD-ljud istället för spelets ljud, om tillgängligt"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "Använd Windows muspekare"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr ""
"Använd Windows muspekare (mindre och svartvit) istället för DOS-pekaren"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "Använd silverpekare"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"Använd de alternativa silverpekarna istället för de normala guldpekarna"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Visa etiketter"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "Mata in skivan %c och tryck på knappen för att fortsätta."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "Kunde inte hitta %s, (%c%d) tryck på knappen."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "Fel vid inläsning av skivan %c, (%c%d) tryck på knappen."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "Spelet pausat. Tryck MELLANSLAG för att fortsätta."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "Är du säker på att du vill starta om? (J/N)J"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "Är du säker på att du vill avsluta? (J/N)J"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "Spela"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "Mata in skiva för spardata"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "Du måste ange ett namn"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "Spelet sprades EJ (skivan full?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "Spelet laddades EJ"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "Sparar '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "Laddar '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "Namnge ditt SPARADE spel"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "Välj ett spel att LADDA"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "Speltitel)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~F~öregående"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~N~ästa"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "Endast tal"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "Tal och undertexter"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "Endast undertexter"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "Tal & text"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "Välj en skicklighetsnivå."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "Hänvisa till din Loom(TM)-manual för hjälp."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "Övning"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "Expert"
@@ -3495,23 +3613,23 @@ msgstr "Flyg åt höger"
msgid "Fly to lower right"
msgstr "Flyg åt nedre höger"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "Snäpprullning på"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "Snäpprullning av"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "Musikvolym: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "Texthastighet: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3520,7 +3638,7 @@ msgstr ""
"Stöd för Native MIDI kräver Roland-uppdateringen från LucasArts,\n"
"men %s saknas. Använder AdLib istället."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3699,12 +3817,21 @@ msgstr "Visa etiketter"
msgid "Show labels for objects on mouse hover"
msgstr "Visar etiketter för objekten som musen pekar på"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr "Du har inte 'teenagent.dat'-filen. Hämta den från ScummVM:s webbsida"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
@@ -3803,9 +3930,6 @@ msgstr ""
#~ msgid "Active filter mode: Nearest"
#~ msgstr "Aktivt filterläge: Närmast"
-#~ msgid "Enable Roland GS Mode"
-#~ msgstr "Aktivera Roland GS-läge"
-
#~ msgctxt "lowres"
#~ msgid "Add Game..."
#~ msgstr "Lägg till spel..."
diff --git a/po/uk_UA.po b/po/uk_UA.po
index 5ab87a4155..232138e930 100644
--- a/po/uk_UA.po
+++ b/po/uk_UA.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: ScummVM 1.3.0svn\n"
"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
-"POT-Creation-Date: 2016-02-20 21:22+0000\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
"PO-Revision-Date: 2015-11-06 10:07+0300\n"
"Last-Translator: Eugene Sandulenko <sev@scummvm.org>\n"
"Language-Team: Ukrainian\n"
@@ -55,15 +55,16 @@ msgstr "²ÓÞàã"
#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
-#: gui/KeysDialog.cpp:43 gui/launcher.cpp:351 gui/massadd.cpp:95
-#: gui/options.cpp:1237 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:70
-#: gui/recorderdialog.cpp:156 gui/saveload-dialog.cpp:216
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
-#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55 engines/engine.cpp:546
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
#: backends/events/default/default-events.cpp:196
#: backends/events/default/default-events.cpp:218
#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
-#: engines/parallaction/saveload.cpp:274 engines/scumm/dialogs.cpp:191
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
#: engines/sword1/control.cpp:865
msgid "Cancel"
msgstr "²öÔÜöÝÐ"
@@ -102,7 +103,7 @@ msgid "Do you really want to overwrite the file?"
msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ×ÐÜöÝØâØ æÕÙ äÐÙÛ?"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -112,7 +113,7 @@ msgid "Yes"
msgstr "ÂÐÚ"
#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
-#: gui/launcher.cpp:795 gui/launcher.cpp:943 gui/launcher.cpp:1002
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
#: backends/events/symbiansdl/symbiansdl-events.cpp:186
#: backends/platform/wince/CEActionsPocket.cpp:326
#: backends/platform/wince/CEActionsSmartphone.cpp:287
@@ -173,7 +174,7 @@ msgstr "ÁØÝãáÞ÷ÔÐ"
msgid "Triangle"
msgstr "ÂàØÚãâÝØÚ"
-#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1168
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
msgid "Misc"
msgstr "Àö×ÝÕ"
@@ -205,14 +206,14 @@ msgstr "ÁÚØÝãâØ"
msgid "Reset all FluidSynth settings to their default values."
msgstr "ÁÚØÝãâØ Òáö ÝÐÛÐèâãÒÐÝÝï FluidSynth ÔÞ ÷å ×ÝÐçÕÝì ×Ð ×ÐÜÞÒçÕÝÝïÜ"
-#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:352
-#: gui/launcher.cpp:1050 gui/launcher.cpp:1054 gui/massadd.cpp:92
-#: gui/options.cpp:1238 gui/saveload-dialog.cpp:932 engines/engine.cpp:465
-#: engines/engine.cpp:476 backends/platform/wii/options.cpp:47
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
#: backends/platform/wince/CELauncherDialog.cpp:54
-#: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49
-#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274
-#: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1834
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
#: engines/scumm/players/player_v3m.cpp:130
#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
@@ -242,15 +243,15 @@ msgstr "·ÐÚàØâØ"
msgid "Mouse click"
msgstr "ºÛöÚ ÜØèÚÞî"
-#: gui/gui-manager.cpp:126 base/main.cpp:322
+#: gui/gui-manager.cpp:126 base/main.cpp:328
msgid "Display keyboard"
msgstr "¿ÞÚÐ×ÐâØ ÚÛÐÒöÐâãàã"
-#: gui/gui-manager.cpp:130 base/main.cpp:326
+#: gui/gui-manager.cpp:130 base/main.cpp:332
msgid "Remap keys"
msgstr "¿ÕàÕßàØ×ÝÐçØâØ ÚÛÐÒöèö"
-#: gui/gui-manager.cpp:133 base/main.cpp:329 engines/scumm/help.cpp:87
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
msgid "Toggle fullscreen"
msgstr "¿ÕàÕÜÚÝãâØ ßÞÒÝÞÕÚàÐÝÝØÙ àÕÖØÜ"
@@ -326,8 +327,8 @@ msgstr ""
"¼ÞÒÐ ÓàØ. ·ÜöÝÐ æìÞÓÞ ÝÐÛÐèâãÒÐÝÝï ÝÕ ßÕàÕâÒÞàØâì Óàã ÐÝÓÛöÙáìÚÞî ÝÐ "
"ãÚàÐ÷ÝáìÚã"
-#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:87
-#: gui/options.cpp:735 gui/options.cpp:748 gui/options.cpp:1208
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
#: audio/null.cpp:41
msgid "<default>"
msgstr "<×Ð ãÜÞÒçÐÝÝïÜ>"
@@ -349,11 +350,11 @@ msgstr "¿ÛÐâäÞàÜÐ:"
msgid "Engine"
msgstr "´ÒØÖÞÚ"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "Graphics"
msgstr "³àÐäöÚÐ"
-#: gui/launcher.cpp:245 gui/options.cpp:1071 gui/options.cpp:1088
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
msgid "GFX"
msgstr "³àä"
@@ -366,7 +367,7 @@ msgctxt "lowres"
msgid "Override global graphic settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ ÓàÐäöÚØ"
-#: gui/launcher.cpp:257 gui/options.cpp:1094
+#: gui/launcher.cpp:257 gui/options.cpp:1096
msgid "Audio"
msgstr "°ãÔöÞ"
@@ -379,11 +380,11 @@ msgctxt "lowres"
msgid "Override global audio settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ ÐãÔöÞ"
-#: gui/launcher.cpp:271 gui/options.cpp:1099
+#: gui/launcher.cpp:271 gui/options.cpp:1101
msgid "Volume"
msgstr "³ãçÝöáâì"
-#: gui/launcher.cpp:273 gui/options.cpp:1101
+#: gui/launcher.cpp:273 gui/options.cpp:1103
msgctxt "lowres"
msgid "Volume"
msgstr "³ãçÝ."
@@ -397,216 +398,217 @@ msgctxt "lowres"
msgid "Override global volume settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ ÓãçÝÞáâö"
-#: gui/launcher.cpp:286 gui/options.cpp:1109
+#: gui/launcher.cpp:287 gui/options.cpp:1111
msgid "MIDI"
msgstr "MIDI"
-#: gui/launcher.cpp:289
+#: gui/launcher.cpp:290
msgid "Override global MIDI settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ MIDI"
-#: gui/launcher.cpp:291
+#: gui/launcher.cpp:292
msgctxt "lowres"
msgid "Override global MIDI settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ MIDI"
-#: gui/launcher.cpp:300 gui/options.cpp:1115
+#: gui/launcher.cpp:302 gui/options.cpp:1121
msgid "MT-32"
msgstr "MT-32"
-#: gui/launcher.cpp:303
+#: gui/launcher.cpp:305
msgid "Override global MT-32 settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ MT-32"
-#: gui/launcher.cpp:305
+#: gui/launcher.cpp:307
msgctxt "lowres"
msgid "Override global MT-32 settings"
msgstr "¿ÕàÕÚàØâØ ÓÛÞÑÐÛìÝö ãáâÐÝÞÒÚØ MT-32"
-#: gui/launcher.cpp:314 gui/options.cpp:1122
+#: gui/launcher.cpp:316 gui/options.cpp:1128
msgid "Paths"
msgstr "ÈÛïåØ"
-#: gui/launcher.cpp:316 gui/options.cpp:1124
+#: gui/launcher.cpp:318 gui/options.cpp:1130
msgctxt "lowres"
msgid "Paths"
msgstr "ÈÛïåØ"
-#: gui/launcher.cpp:323
+#: gui/launcher.cpp:325
msgid "Game Path:"
msgstr "ÈÛïå ÔÞ ÓàØ:"
-#: gui/launcher.cpp:325
+#: gui/launcher.cpp:327
msgctxt "lowres"
msgid "Game Path:"
msgstr "ÈÛïå ÔÞ ÓàØ:"
-#: gui/launcher.cpp:330 gui/options.cpp:1148
+#: gui/launcher.cpp:332 gui/options.cpp:1154
msgid "Extra Path:"
msgstr "´ÞÔÐâÚ. èÛïå:"
-#: gui/launcher.cpp:330 gui/launcher.cpp:332 gui/launcher.cpp:333
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
msgid "Specifies path to additional data used by the game"
msgstr "²ÚÐ×ãô èÛïå ÔÞ ÔÞÔÐâÚÞÒØå äÐÙÛöÒ ÔÐÝØå ÔÛï ÓàØ"
-#: gui/launcher.cpp:332 gui/options.cpp:1150
+#: gui/launcher.cpp:334 gui/options.cpp:1156
msgctxt "lowres"
msgid "Extra Path:"
msgstr "´ÞÔ. èÛïå:"
-#: gui/launcher.cpp:339 gui/options.cpp:1132
+#: gui/launcher.cpp:341 gui/options.cpp:1138
msgid "Save Path:"
msgstr "ÈÛïå ×ÑÕà.:"
-#: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342
-#: gui/options.cpp:1132 gui/options.cpp:1134 gui/options.cpp:1135
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
msgid "Specifies where your saved games are put"
msgstr "²ÚÐ×ãô èÛïå ÔÞ ×ÑÕàÕÖÕÝì ÓàØ"
-#: gui/launcher.cpp:341 gui/options.cpp:1134
+#: gui/launcher.cpp:343 gui/options.cpp:1140
msgctxt "lowres"
msgid "Save Path:"
msgstr "ÈÛïå ×ÑÕà.:"
-#: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517
-#: gui/launcher.cpp:571 gui/options.cpp:1143 gui/options.cpp:1151
-#: gui/options.cpp:1160 gui/options.cpp:1275 gui/options.cpp:1281
-#: gui/options.cpp:1289 gui/options.cpp:1319 gui/options.cpp:1325
-#: gui/options.cpp:1332 gui/options.cpp:1425 gui/options.cpp:1428
-#: gui/options.cpp:1440
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
msgctxt "path"
msgid "None"
msgstr "½Õ ×ÐÒÔÐÝØÙ"
-#: gui/launcher.cpp:365 gui/launcher.cpp:465 gui/launcher.cpp:575
-#: gui/options.cpp:1269 gui/options.cpp:1313 gui/options.cpp:1431
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
#: backends/platform/wii/options.cpp:56
msgid "Default"
msgstr "·Ð ãÜÞÒçÐÝÝïÜ"
-#: gui/launcher.cpp:510 gui/options.cpp:1434
+#: gui/launcher.cpp:512 gui/options.cpp:1469
msgid "Select SoundFont"
msgstr "²ØÑÕàöâì SoundFont"
-#: gui/launcher.cpp:529 gui/launcher.cpp:682
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
msgid "Select directory with game data"
msgstr "²ØÑÕàöâì ßÐßÚã × äÐÙÛÐÜØ ÓàØ"
-#: gui/launcher.cpp:547
+#: gui/launcher.cpp:549
msgid "Select additional game directory"
msgstr "²ØÑÕàöâì ÔÞÔÐâÚÞÒã ßÐßÚã ÓàØ"
-#: gui/launcher.cpp:559 gui/options.cpp:1377
+#: gui/launcher.cpp:561 gui/options.cpp:1412
msgid "Select directory for saved games"
msgstr "²ØÑÕàöâì ßÐßÚã ÔÛï ×ÑÕàÕÖÕÝì"
-#: gui/launcher.cpp:586
+#: gui/launcher.cpp:588
msgid "This game ID is already taken. Please choose another one."
msgstr "ÆÕÙ ID ÓàØ ÒÖÕ ÒØÚÞàØáâÞÒãôâìáï. ±ãÔì ÛÐáÚÐ, ÒØÑÕàöâì öÝèØÙ."
-#: gui/launcher.cpp:626 engines/dialogs.cpp:111
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
msgid "~Q~uit"
msgstr "~²~ØåöÔ"
-#: gui/launcher.cpp:626 backends/platform/sdl/macosx/appmenu_osx.mm:106
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
msgid "Quit ScummVM"
msgstr "²ØåöÔ ×ö ScummVM"
-#: gui/launcher.cpp:627
+#: gui/launcher.cpp:629
msgid "A~b~out..."
msgstr "¿àÞ ß~à~ÞÓàÐÜã..."
-#: gui/launcher.cpp:627 backends/platform/sdl/macosx/appmenu_osx.mm:80
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
msgid "About ScummVM"
msgstr "¿àÞ ScummVM"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "~O~ptions..."
msgstr "~½~ÐÛÐèâãÒÐÝÝï"
-#: gui/launcher.cpp:628
+#: gui/launcher.cpp:630
msgid "Change global ScummVM options"
msgstr "·ÜöÝØâØ ÓÛÞÑÐÛìÝö ÝÐÛÐèâãÒÐÝÝï ScummVM"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "~S~tart"
msgstr "·~Ð~ßãáÚ"
-#: gui/launcher.cpp:630
+#: gui/launcher.cpp:632
msgid "Start selected game"
msgstr "·ÐßãáâØâØ ÒØÑàÐÝã Óàã"
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "~L~oad..."
msgstr "~·~ÐÒÐÝâÐÖØâØ..."
-#: gui/launcher.cpp:633
+#: gui/launcher.cpp:635
msgid "Load saved game for selected game"
msgstr "·ÐÒÐÝâÐÖØâØ ×ÑÕàÕÖÕÝÝï ÔÛï ÒØÑàÐÝÞ÷ ÓàØ"
-#: gui/launcher.cpp:638
+#: gui/launcher.cpp:640
msgid "~A~dd Game..."
msgstr "~´~ÞÔÐâØ Óàã..."
-#: gui/launcher.cpp:638 gui/launcher.cpp:645
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
msgid "Hold Shift for Mass Add"
msgstr "ÃâàØÜãÙâÕ ÚÛÐÒöèã Shift ÔÛï âÞÓÞ, éÞÑ ÔÞÔÐâØ ÔÕÚöÛìÚÐ öÓÞà"
-#: gui/launcher.cpp:640
+#: gui/launcher.cpp:642
msgid "~E~dit Game..."
msgstr "ÀÕÔÐ~Ó~ãÒÐâØ Óàã"
-#: gui/launcher.cpp:640 gui/launcher.cpp:647
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
msgid "Change game options"
msgstr "·ÜöÝØâØ ÝÐÛÐèâãÒÐÝÝï ÓàØ"
-#: gui/launcher.cpp:642
+#: gui/launcher.cpp:644
msgid "~R~emove Game"
msgstr "~²~ØÔÐ󯉯 Óàã"
-#: gui/launcher.cpp:642 gui/launcher.cpp:649
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
msgid "Remove game from the list. The game data files stay intact"
msgstr "²ØÔÐ󯉯 Óàã ×ö áߨáÚã. ½Õ ÒØÔÐÛïô Óàã × ÖÞàáâÚÞÓÞ ÔØáÚã"
-#: gui/launcher.cpp:645
+#: gui/launcher.cpp:647
msgctxt "lowres"
msgid "~A~dd Game..."
msgstr "~´~ÞÔÐâØ Óàã..."
-#: gui/launcher.cpp:647
+#: gui/launcher.cpp:649
msgctxt "lowres"
msgid "~E~dit Game..."
msgstr "ÀÕÔÐ~Ó~. Óàã..."
-#: gui/launcher.cpp:649
+#: gui/launcher.cpp:651
msgctxt "lowres"
msgid "~R~emove Game"
msgstr "~²~ØÔÐ󯉯 Óàã"
-#: gui/launcher.cpp:657
+#: gui/launcher.cpp:659
msgid "Search in game list"
msgstr "¿ÞèãÚ ã áߨáÚã öÓÞà"
-#: gui/launcher.cpp:661 gui/launcher.cpp:1224
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
msgid "Search:"
msgstr "¿ÞèãÚ:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
-#: engines/mohawk/riven.cpp:718 engines/pegasus/pegasus.cpp:353
-#: engines/tsage/scenes.cpp:600
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
msgid "Load game:"
msgstr "·ÐÒÐÝâÐÖØâØ Óàã:"
-#: gui/launcher.cpp:685 engines/dialogs.cpp:115
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/cruise/menu.cpp:214 engines/mohawk/riven.cpp:718
-#: engines/parallaction/saveload.cpp:197 engines/pegasus/pegasus.cpp:353
-#: engines/scumm/dialogs.cpp:189 engines/tsage/scenes.cpp:600
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
msgid "Load"
msgstr "·ÐÒÐÝâÐÖØâØ"
-#: gui/launcher.cpp:794
+#: gui/launcher.cpp:796
msgid ""
"Do you really want to run the mass game detector? This could potentially add "
"a huge number of games."
@@ -614,39 +616,39 @@ msgstr ""
"ÇØ ÒØ ÔöÙáÝÞ åÞçÕâÕ ×ÐßãáâØâØ ßÞèãÚ ãáöå öÓÞà? ÆÕ ßÞâÕÝæöÙÝÞ ÜÞÖÕ ÔÞÔÐâØ "
"ÒÕÛØÚã ÚöÛìÚöáâì öÓÞà."
-#: gui/launcher.cpp:843
+#: gui/launcher.cpp:845
msgid "ScummVM couldn't open the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕ ÒöÔÚàØâØ ÒÚÐ×ÐÝã ßÐßÚã!"
-#: gui/launcher.cpp:855
+#: gui/launcher.cpp:857
msgid "ScummVM could not find any game in the specified directory!"
msgstr "ScummVM ÝÕ ÜÞÖÕ ×ÝÐÙâØ Óàã ã ÒÚÐ×ÐÝöÙ ßÐßæö!"
-#: gui/launcher.cpp:869
+#: gui/launcher.cpp:871
msgid "Pick the game:"
msgstr "²ØÑÕàöâì Óàã:"
-#: gui/launcher.cpp:943
+#: gui/launcher.cpp:945
msgid "Do you really want to remove this game configuration?"
msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÔÐ󯉯 ãáâÐÝÞÒÚØ ÔÛï æöô÷ ÓàØ?"
-#: gui/launcher.cpp:1001
+#: gui/launcher.cpp:1003
msgid "Do you want to load saved game?"
msgstr "²Ø åÞçÕâÕ ×ÐÒÐÝâÐÖØâØ ×ÑÕàÕÖÕÝã Óàã?"
-#: gui/launcher.cpp:1050
+#: gui/launcher.cpp:1052
msgid "This game does not support loading games from the launcher."
msgstr "Æï ÓàÐ ÝÕ ßöÔâàØÜãô ×ÐÒÐÝâÐÖÕÝÝï ×ÑÕàÕÖÕÝì çÕàÕ× ÓÞÛÞÒÝÕ ÜÕÝî."
-#: gui/launcher.cpp:1054
+#: gui/launcher.cpp:1056
msgid "ScummVM could not find any engine capable of running the selected game!"
msgstr "ScummVM ÝÕ ×ÜöÓ ×ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚã ÒØÑàÐÝÞ÷ ÓàØ!"
-#: gui/launcher.cpp:1161
+#: gui/launcher.cpp:1163
msgid "Mass Add..."
msgstr "´ÞÔ. ÑÐÓÐâÞ..."
-#: gui/launcher.cpp:1163
+#: gui/launcher.cpp:1165
msgid "Record..."
msgstr "·Ðߨá..."
@@ -689,132 +691,132 @@ msgstr "¿ÕàÕÚÛîçØâØáï ÝÐ Óàã"
msgid "Fast replay"
msgstr "ÈÒØÔÚÕ ÒöÔâÒÞàÕÝÝï"
-#: gui/options.cpp:85
+#: gui/options.cpp:87 common/updates.cpp:56
msgid "Never"
msgstr "½öÚÞÛØ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 5 mins"
msgstr "ÚÞÖÝö 5 åÒ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 10 mins"
msgstr "ÚÞÖÝö 10 åÒ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 15 mins"
msgstr "ÚÞÖÝö 15 åÒ"
-#: gui/options.cpp:85
+#: gui/options.cpp:87
msgid "every 30 mins"
msgstr "ÚÞÖÝö 30 åÒ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "8 kHz"
msgstr "8 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "11 kHz"
msgstr "11 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "22 kHz"
msgstr "22 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "44 kHz"
msgstr "44 Ú³æ"
-#: gui/options.cpp:87
+#: gui/options.cpp:89
msgid "48 kHz"
msgstr "48 Ú³æ"
-#: gui/options.cpp:255 gui/options.cpp:479 gui/options.cpp:580
-#: gui/options.cpp:649 gui/options.cpp:857
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
msgctxt "soundfont"
msgid "None"
msgstr "½Õ ×ÐÔÐÝØÙ"
-#: gui/options.cpp:389
+#: gui/options.cpp:395
msgid "Failed to apply some of the graphic options changes:"
msgstr "½Õ ÒÔÐÛÞáï ×ÐáâÞáãÒÐâØ ÔÕïÚö ×ö ×ÜöÝ ÓàÐäöçÝØå ÝÐÛÐèâãÒÐÝì:"
-#: gui/options.cpp:401
+#: gui/options.cpp:407
msgid "the video mode could not be changed."
msgstr "ÝÕ ÒÔÐÛÞáï ×ÜöÝØâØ ÓàÐäöçÝØÙ àÕÖØÜ."
-#: gui/options.cpp:407
+#: gui/options.cpp:413
msgid "the fullscreen setting could not be changed"
msgstr "ÝÕ ÒÔÐÛÞáï ×ÜöÝØâØ àÕÖØÜ ßÞÒÝÞÓÞ ÕÚàÐÝã"
-#: gui/options.cpp:413
+#: gui/options.cpp:419
msgid "the aspect ratio setting could not be changed"
msgstr "ÝÕ ÒÔÐÛÞáï ×ÜöÝØâØ àÕÖØÜ ÚÞàÕÚæö÷ áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ"
-#: gui/options.cpp:732
+#: gui/options.cpp:738
msgid "Graphics mode:"
msgstr "³àÐäöçÝ. àÕÖØÜ:"
-#: gui/options.cpp:746
+#: gui/options.cpp:752
msgid "Render mode:"
msgstr "ÀÕÖØÜ àÐáâàãÒ.:"
-#: gui/options.cpp:746 gui/options.cpp:747
+#: gui/options.cpp:752 gui/options.cpp:753
msgid "Special dithering modes supported by some games"
msgstr "ÁßÕæöÐÛìÝö àÕÖØÜØ àÐáâàãÒÐÝÝï, ïÚö ßöÔâàØÜãîâì ÔÕïÚö öÓàØ"
-#: gui/options.cpp:758
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
msgid "Fullscreen mode"
msgstr "¿ÞÒÝÞÕÚàÐÝÝØÙ àÕÖØÜ"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Aspect ratio correction"
msgstr "ºÞàÕÚæöï áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ"
-#: gui/options.cpp:761
+#: gui/options.cpp:767
msgid "Correct aspect ratio for 320x200 games"
msgstr "ºÞàØÓãÒÐâØ áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ÔÛï öÓÞà × ÓàÐäöÚÞî 320x200"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Preferred Device:"
msgstr "ÃßÞÔÞÑÐÝØÙ ßàØáâàöÙ:"
-#: gui/options.cpp:769
+#: gui/options.cpp:775
msgid "Music Device:"
msgstr "¼ãרç. ßàØáâàöÙ:"
-#: gui/options.cpp:769 gui/options.cpp:771
+#: gui/options.cpp:775 gui/options.cpp:777
msgid "Specifies preferred sound device or sound card emulator"
msgstr "²ÚÐ×ãô ãßÞÔÞÑÐÝØÙ ×ÒãÚÞÒØÙ ßàØáâàöÙ ÐÑÞ ÕÜãÛïâÞà ×ÒãÚÞÒÞ÷ ÚÐàâØ"
-#: gui/options.cpp:769 gui/options.cpp:771 gui/options.cpp:772
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
msgid "Specifies output sound device or sound card emulator"
msgstr "²ÚÐ×ãô ÒØåöÔÝØÙ ×ÒãÚÞÒØÙ ßàØáâàöÙ ÐÑÞ ÕÜãÛïâÞà ×ÒãÚÞÒÞ÷ ÚÐàâØ"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Preferred Dev.:"
msgstr "ÃßÞÔÞÑ. ßàØáâàöÙ:"
-#: gui/options.cpp:771
+#: gui/options.cpp:777
msgctxt "lowres"
msgid "Music Device:"
msgstr "¼ãרçÝØÙ ßàØáâàöÙ:"
-#: gui/options.cpp:798
+#: gui/options.cpp:804
msgid "AdLib emulator:"
msgstr "µÜãÛïâÞà AdLib:"
-#: gui/options.cpp:798 gui/options.cpp:799
+#: gui/options.cpp:804 gui/options.cpp:805
msgid "AdLib is used for music in many games"
msgstr "·ÒãÚÞÒÐ ÚÐàâÐ AdLib ÒØÚÞàØáâÞÒãôâìáï ÑÐÓÐâìÜÐ öÓàÐÜØ"
-#: gui/options.cpp:809
+#: gui/options.cpp:815
msgid "Output rate:"
msgstr "²ØåöÔÝÐ çÐáâÞâÐ:"
-#: gui/options.cpp:809 gui/options.cpp:810
+#: gui/options.cpp:815 gui/options.cpp:816
msgid ""
"Higher value specifies better sound quality but may be not supported by your "
"soundcard"
@@ -822,67 +824,63 @@ msgstr ""
"²ÕÛØÚö ×ÝÐçÕÝÝï ×ÐÔÐîâì ÚàÐéã ïÚöáâì ×ÒãÚã, ßàÞâÕ ÒÞÝØ ÜÞÖãâì ÝÕ "
"ßöÔâàØÜãÒÐâØáï ÒÐèÞî ×ÒãÚÞÒÞî ÚÐàâÞî"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "GM Device:"
msgstr "¿àØáâàöÙ GM:"
-#: gui/options.cpp:820
+#: gui/options.cpp:826
msgid "Specifies default sound device for General MIDI output"
msgstr "²ÚÐ×ãô ÒØåöÔÝØÙ ×ÒãÚÞÒØÙ ßàØáâàöÙ ÔÛï General MIDI"
-#: gui/options.cpp:831
+#: gui/options.cpp:837
msgid "Don't use General MIDI music"
msgstr "½Õ ÒØÚÞàØáâÞÒãÒÐâØ ÜãרÚã General MIDI"
-#: gui/options.cpp:842 gui/options.cpp:908
+#: gui/options.cpp:848 gui/options.cpp:910
msgid "Use first available device"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ ßÕàèØÙ ÝÐïÒÝØÙ ßàØáâàöÙ"
-#: gui/options.cpp:854
+#: gui/options.cpp:860
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:854 gui/options.cpp:856 gui/options.cpp:857
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
msgstr ""
"SoundFont ßöÔâàØÜãôâìáï ÔÕïÚØÜØ ×ÒãÚÞÒØÜØ ÚÐàâÐÜØ, FluidSynth âÐ Timidity"
-#: gui/options.cpp:856
+#: gui/options.cpp:862
msgctxt "lowres"
msgid "SoundFont:"
msgstr "SoundFont:"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Mixed AdLib/MIDI mode"
msgstr "·ÜöèÐÝØÙ àÕÖØÜ AdLib/MIDI"
-#: gui/options.cpp:862
+#: gui/options.cpp:868
msgid "Use both MIDI and AdLib sound generation"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ ö MIDI ö AdLib ÔÛï ÓÕÝÕàÐæö÷ ×ÒãÚã"
-#: gui/options.cpp:865
+#: gui/options.cpp:871
msgid "MIDI gain:"
msgstr "¿ÞáØÛÕÝÝï MIDI:"
-#: gui/options.cpp:872
-msgid "FluidSynth Settings"
-msgstr "½ÐÛÐèâãÒÐÝÝï FluidSynth"
-
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "MT-32 Device:"
msgstr "¿àØáâàöÙ MT-32:"
-#: gui/options.cpp:879
+#: gui/options.cpp:881
msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
msgstr ""
"²ÚÐ×ãô ×ÒãÚÞÒØÙ ßàØáâàöÙ ×Ð ãÜÞÒçÐÝÝïÜ ÔÛï ÒØÒÞÔã ÝÐ Roland MT-32/LAPC1/"
"CM32l/CM64"
-#: gui/options.cpp:884
+#: gui/options.cpp:886
msgid "True Roland MT-32 (disable GM emulation)"
msgstr "ÁßàÐÒÖÝöÙ Roland MT-32 (ÒØÜÚÝãâØ ÕÜãÛïæØî GM)"
-#: gui/options.cpp:884 gui/options.cpp:886
+#: gui/options.cpp:886 gui/options.cpp:888
msgid ""
"Check if you want to use your real hardware Roland-compatible sound device "
"connected to your computer"
@@ -890,16 +888,16 @@ msgstr ""
"²öÔÜöâìâÕ, ïÚéÞ ã ÒÐá ßöÔÚÛîçÕÝÞ Roland-áãÜöáÝØÙ ×ÒãÚÞÒØÙ ßàØáâàöÙ ö ÒØ "
"åÞçÕâÕ ÙÞÓÞ ÒØÚÞàØáâÞÒãÒÐâØ"
-#: gui/options.cpp:886
+#: gui/options.cpp:888
msgctxt "lowres"
msgid "True Roland MT-32 (no GM emulation)"
msgstr "ÁßàÐÒÖÝöÙ Roland MT-32 (ÒØÜÚÝãâØ ÕÜãÛïæØî GM)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid "Roland GS Device (enable MT-32 mappings)"
msgstr "ÀÕÖØÜ Roland GS (ÒÒöÜÚÝãâØ ÜÐßÛÕÝÝï MT-32)"
-#: gui/options.cpp:889
+#: gui/options.cpp:891
msgid ""
"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
"GS device"
@@ -907,171 +905,187 @@ msgstr ""
"²öÔÜöâìâÕ, ïÚéÞ åÞçÕâÕ ÒÚÛîçØâØ ÛÐâÚØ ÔÛï öáâàãÜÕÝâöÒ ÔÛï ÕÜãÛïæö÷ MT-32 ÝÐ "
"Roland"
-#: gui/options.cpp:898
+#: gui/options.cpp:900
msgid "Don't use Roland MT-32 music"
msgstr "½Õ ÒØÚÞàØáâÞÒãÒÐâØ ÜãרÚã ÔÛï Roland MT-32"
-#: gui/options.cpp:925
+#: gui/options.cpp:927
msgid "Text and Speech:"
msgstr "ÂÕÚáâ ö Þ×ÒãçÚÐ:"
-#: gui/options.cpp:929 gui/options.cpp:939
+#: gui/options.cpp:931 gui/options.cpp:941
msgid "Speech"
msgstr "¾×ÒãçÚÐ"
-#: gui/options.cpp:930 gui/options.cpp:940
+#: gui/options.cpp:932 gui/options.cpp:942
msgid "Subtitles"
msgstr "ÁãÑâØâàØ"
-#: gui/options.cpp:931
+#: gui/options.cpp:933
msgid "Both"
msgstr "²áÕ"
-#: gui/options.cpp:933
+#: gui/options.cpp:935
msgid "Subtitle speed:"
msgstr "ÈÒØÔ. áãÑâØâàöÒ:"
-#: gui/options.cpp:935
+#: gui/options.cpp:937
msgctxt "lowres"
msgid "Text and Speech:"
msgstr "ÂÕÚáâ ö Þ×ÒãçÚÐ:"
-#: gui/options.cpp:939
+#: gui/options.cpp:941
msgid "Spch"
msgstr "¾×Ò"
-#: gui/options.cpp:940
+#: gui/options.cpp:942
msgid "Subs"
msgstr "狄"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgctxt "lowres"
msgid "Both"
msgstr "²áÕ"
-#: gui/options.cpp:941
+#: gui/options.cpp:943
msgid "Show subtitles and play speech"
msgstr "¿ÞÚÐ×ãÒÐâØ áãÑâØâàØ ö ÒöÔâÒÞàîÒÐâØ ÜÞÒã"
-#: gui/options.cpp:943
+#: gui/options.cpp:945
msgctxt "lowres"
msgid "Subtitle speed:"
msgstr "ÈÒØÔ. áãÑâØâàöÒ:"
-#: gui/options.cpp:959
+#: gui/options.cpp:961
msgid "Music volume:"
msgstr "³ãçÝöáâì Üã×ØÚØ:"
-#: gui/options.cpp:961
+#: gui/options.cpp:963
msgctxt "lowres"
msgid "Music volume:"
msgstr "³ãçÝöáâì Üã×ØÚØ:"
-#: gui/options.cpp:968
+#: gui/options.cpp:970
msgid "Mute All"
msgstr "²ØÜÚÝãâØ ÒáÕ"
-#: gui/options.cpp:971
+#: gui/options.cpp:973
msgid "SFX volume:"
msgstr "³ãçÝöáâì ÕäÕÚâöÒ:"
-#: gui/options.cpp:971 gui/options.cpp:973 gui/options.cpp:974
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
msgid "Special sound effects volume"
msgstr "³ãçÝöáâì áßÕæöÐÛìÝØå ×ÒãÚÞÒØå ÕäÕÚâöÒ"
-#: gui/options.cpp:973
+#: gui/options.cpp:975
msgctxt "lowres"
msgid "SFX volume:"
msgstr "³ãçÝ. ÕäÕÚâöÒ:"
-#: gui/options.cpp:981
+#: gui/options.cpp:983
msgid "Speech volume:"
msgstr "³ãçÝöáâì Þ×ÒãçÚØ:"
-#: gui/options.cpp:983
+#: gui/options.cpp:985
msgctxt "lowres"
msgid "Speech volume:"
msgstr "³ãçÝ. Þ×ÒãçÚØ:"
-#: gui/options.cpp:1140
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "½ÐÛÐèâãÒÐÝÝï FluidSynth"
+
+#: gui/options.cpp:1146
msgid "Theme Path:"
msgstr "ÈÛïå ÔÞ âÕÜ:"
-#: gui/options.cpp:1142
+#: gui/options.cpp:1148
msgctxt "lowres"
msgid "Theme Path:"
msgstr "ÈÛïå ÔÞ âÕÜ:"
-#: gui/options.cpp:1148 gui/options.cpp:1150 gui/options.cpp:1151
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
msgid "Specifies path to additional data used by all games or ScummVM"
msgstr ""
"²ÚÐ×ãô èÛïå ÔÞ ÔÞÔÐâÚÞÒØå äÐÙÛöÒ ÔÐÝØå, ïÚö ÒØÚÞàØáâÞÒãîâìáï ãáöÜÐ öÓàÐÜØ "
"ÐÑÞ ScummVM"
-#: gui/options.cpp:1157
+#: gui/options.cpp:1163
msgid "Plugins Path:"
msgstr "ÈÛïå ÔÞ ÒâãÛÚöÒ:"
-#: gui/options.cpp:1159
+#: gui/options.cpp:1165
msgctxt "lowres"
msgid "Plugins Path:"
msgstr "ÈÛïå ÔÞ ÒâãÛÚöÒ:"
-#: gui/options.cpp:1170
+#: gui/options.cpp:1176
msgctxt "lowres"
msgid "Misc"
msgstr "Àö×ÝÕ"
-#: gui/options.cpp:1172
+#: gui/options.cpp:1178
msgid "Theme:"
msgstr "ÂÕÜÐ:"
-#: gui/options.cpp:1176
+#: gui/options.cpp:1182
msgid "GUI Renderer:"
msgstr "ÀÐáâÕà. GUI:"
-#: gui/options.cpp:1188
+#: gui/options.cpp:1194
msgid "Autosave:"
msgstr "°ÒâÞ×ÑÕàÕÖÕÝÝï:"
-#: gui/options.cpp:1190
+#: gui/options.cpp:1196
msgctxt "lowres"
msgid "Autosave:"
msgstr "°ÒâÞ×ÑÕàÕÖ.:"
-#: gui/options.cpp:1198
+#: gui/options.cpp:1204
msgid "Keys"
msgstr "ºÛÐÒöèö"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "GUI Language:"
msgstr "¼ÞÒÐ öÝâÕàä.:"
-#: gui/options.cpp:1205
+#: gui/options.cpp:1211
msgid "Language of ScummVM GUI"
msgstr "¼ÞÒÐ ÓàÐäöçÝÞÓÞ öÝâÕàäÕÙáã ScummVM"
-#: gui/options.cpp:1364
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr "¿ÕàÕÒöàïâØ ÞÝÞÒÛÕÝÝï:"
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr "ÏÚ çÐáâÞ ßÕàÕÒöàïâØ ÞÝÞÒÛÕÝÝï ScummVM"
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr "¿ÕàÕÒöàØâØ ×ÐàÐ×"
+
+#: gui/options.cpp:1386
msgid "You have to restart ScummVM before your changes will take effect."
msgstr "²Ø ßÞÒØÝÝö ßÕàÕ×ÐßãáâØâØ ScummVM éÞÑ ×ÐáâÞáãÒÐâØ ×ÜöÝØ."
-#: gui/options.cpp:1384
+#: gui/options.cpp:1419
msgid "The chosen directory cannot be written to. Please select another one."
msgstr "½Õ ÜÞÖã ߨáÐâØ ã ÒØÑàÐÝã ßÐßÚã. ±ãÔì ÛÐáÚÐ, ÒÚÐÖöâì öÝèã."
-#: gui/options.cpp:1393
+#: gui/options.cpp:1428
msgid "Select directory for GUI themes"
msgstr "²ØÑÕàöâì ßÐßÚã ÔÛï âÕÜ GUI"
-#: gui/options.cpp:1403
+#: gui/options.cpp:1438
msgid "Select directory for extra files"
msgstr "²ØÑÕàöâì ßÐßÚã × ÔÞÔÐâÚÞÒØÜØ äÐÙÛÐÜØ"
-#: gui/options.cpp:1414
+#: gui/options.cpp:1449
msgid "Select directory for plugins"
msgstr "²ØÑÕàöâì ßÐßÚã ×ö ÒâãÛÚÐÜØ"
-#: gui/options.cpp:1467
+#: gui/options.cpp:1502
msgid ""
"The theme you selected does not support your current language. If you want "
"to use this theme you need to switch to another language first."
@@ -1088,65 +1102,65 @@ msgstr "# ÝÐáâ"
msgid "add"
msgstr "ÔÞÔ"
-#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:164
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
msgid "Delete char"
msgstr "²ØÔÐ󯉯 áÜÜÒÞÛ"
-#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:168
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
msgid "<"
msgstr "<"
#. I18N: Pre means 'Predictive', leave '*' as is
-#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:572
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
msgid "* Pre"
msgstr "* ¿àÕ"
#. I18N: 'Num' means Numbers
-#: gui/predictivedialog.cpp:575
+#: gui/predictivedialog.cpp:578
msgid "* Num"
msgstr "* Æäà"
#. I18N: 'Abc' means Latin alphabet input
-#: gui/predictivedialog.cpp:578
+#: gui/predictivedialog.cpp:581
msgid "* Abc"
msgstr "* Abc"
-#: gui/recorderdialog.cpp:64
+#: gui/recorderdialog.cpp:63
msgid "Recorder or Playback Gameplay"
msgstr "·ÐߨáãÒÐâØ ÐÑÞ ÒöÔâÒÞàØâØ ßàÞæÕá ÓàØ"
-#: gui/recorderdialog.cpp:69 gui/recorderdialog.cpp:156
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
msgid "Delete"
msgstr "²ØÔÐÛØâØ"
-#: gui/recorderdialog.cpp:71
+#: gui/recorderdialog.cpp:70
msgid "Record"
msgstr "·ÐߨáÐâØ"
-#: gui/recorderdialog.cpp:72
+#: gui/recorderdialog.cpp:71
msgid "Playback"
msgstr "²öÔâÒÞàØâØ"
-#: gui/recorderdialog.cpp:74
+#: gui/recorderdialog.cpp:73
msgid "Edit"
msgstr "ÀÕÔÐÓãÒÐâØ"
-#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
-#: gui/recorderdialog.cpp:253
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
msgid "Author: "
msgstr "°ÒâÞà: "
-#: gui/recorderdialog.cpp:87 gui/recorderdialog.cpp:244
-#: gui/recorderdialog.cpp:254
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
msgid "Notes: "
msgstr "¿àØÜöâÚØ: "
-#: gui/recorderdialog.cpp:155
+#: gui/recorderdialog.cpp:154
msgid "Do you really want to delete this record?"
msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÔÐ󯉯 æÕÙ ×Ðߨá?"
-#: gui/recorderdialog.cpp:174
+#: gui/recorderdialog.cpp:173
msgid "Unknown Author"
msgstr "½ÕÒöÔÞÜØÙ ÐÒâÞà"
@@ -1210,7 +1224,7 @@ msgstr "ÁâÒÞàØâØ ÝÞÒØÙ ×Ðߨá ÓàØ"
msgid "Name: "
msgstr "½Ð×ÒÐ: "
-#: gui/saveload-dialog.cpp:949
+#: gui/saveload-dialog.cpp:951
#, c-format
msgid "Enter a description for slot %d:"
msgstr "²ÒÕÔöâì Þߨá ÔÛï áÛÞâã %d:"
@@ -1219,64 +1233,88 @@ msgstr "²ÒÕÔöâì Þߨá ÔÛï áÛÞâã %d:"
msgid "Select a Theme"
msgstr "²ØÑÕàöâì âÕÜã"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgid "Disabled GFX"
msgstr "±Õ× ÓàÐäöÚØ"
-#: gui/ThemeEngine.cpp:347
+#: gui/ThemeEngine.cpp:415
msgctxt "lowres"
msgid "Disabled GFX"
msgstr "±Õ× ÓàÐäöÚØ"
-#: gui/ThemeEngine.cpp:348
+#: gui/ThemeEngine.cpp:416
msgid "Standard Renderer"
msgstr "ÁâÐÝÔÐàâÝØÙ àÐáâÕàØ×ÐâÞà"
-#: gui/ThemeEngine.cpp:348 engines/scumm/dialogs.cpp:663
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
msgid "Standard"
msgstr "ÁâÐÝÔÐàâÝØÙ"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased Renderer"
msgstr "ÀÐáâÕàØ×ÐâÞà ×ö ×ÓÛÐÔÖãÒÐÝÝïÜ"
-#: gui/ThemeEngine.cpp:350
+#: gui/ThemeEngine.cpp:418
msgid "Antialiased"
msgstr "·ö ×ÓÛÐÔÖãÒÐÝÝïÜ"
-#: gui/widget.cpp:323 gui/widget.cpp:325 gui/widget.cpp:331 gui/widget.cpp:333
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+"ScummVM áâÐÒ ßöÔâàØÜãÒÐâØ ÐÒâÞÜÐâØçÝã ßÕàÕÒöàÚã\n"
+"ÞÝÞÒÛÕÝì, éÞ ßÞâàÕÑãô ÔÞáãßã ÔÞ ¦ÝâÕàÝÕâã.\n"
+"\n"
+"ÇØ åÞâöÛØ Ñ ÒØ ÒÚÛîçØâØ âÐÚã ßÕàÕÒöàÚã?"
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr "(²Ø ×ÐÒÖÔØ ÜÞÖÕâÕ ÒÚÛîçØâØ ÷÷ ã ½ÐÛÐèâãÒÐÝÝïå ÝÐ ×ÐÚÛÐÔæö ¦ÝèÕ)"
+
+#: gui/updates-dialog.cpp:92
+msgid "Check for updates automatically"
+msgstr "°ÒâÞÜÐâëçÝÞ ßÕàÕÒöàïâØ ÞÝÞÒÛÕÝÝï"
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr "¿àÞÔÞÒÖØâØ"
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
msgid "Clear value"
msgstr "¾çØáâØâØ ×ÝÐçÕÝÝï"
-#: base/main.cpp:237
+#: base/main.cpp:243
#, c-format
msgid "Engine does not support debug level '%s'"
msgstr "´ÒØÖÞÚ ÝÕ ßöÔâàØÜãô àöÒÕÝì ÒöÔÛÐÔÚØ '%s'"
-#: base/main.cpp:309
+#: base/main.cpp:315
msgid "Menu"
msgstr "¼ÕÝî"
-#: base/main.cpp:312 backends/platform/symbian/src/SymbianActions.cpp:45
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
#: backends/platform/wince/CEActionsPocket.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:46
msgid "Skip"
msgstr "¿àÞßãáâØâØ"
-#: base/main.cpp:315 backends/platform/symbian/src/SymbianActions.cpp:50
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
#: backends/platform/wince/CEActionsPocket.cpp:42
msgid "Pause"
msgstr "¿Ðã×Ð"
-#: base/main.cpp:318
+#: base/main.cpp:324
msgid "Skip line"
msgstr "¿àÞßãáâØâØ àïÔÞÚ"
-#: base/main.cpp:510
+#: base/main.cpp:524
msgid "Error running game:"
msgstr "¿ÞÜØÛÚÐ ×ÐßãáÚã ÓàØ:"
-#: base/main.cpp:557
+#: base/main.cpp:571
msgid "Could not find any engine capable of running the selected game"
msgstr "½Õ ÜÞÖã ×ÝÐÙâØ ÔÒØÖÞÚ ÔÛï ×ÐßãáÚã ÒØÑàÐÝÞ÷ ÓàØ"
@@ -1371,16 +1409,32 @@ msgctxt "lowres"
msgid "Hercules Amber"
msgstr "Hercules ÑãàèâØÝÝØÙ"
-#: engines/advancedDetector.cpp:317
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr "ÉÞÔÕÝÝÞ"
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr "ÉÞâØÖÝï"
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr "ÉÞÜöáïæï"
+
+#: common/updates.cpp:64
+msgid "<Bad value>"
+msgstr "<½ÕÒöàÝÕ ×ÝÐçÕÝÝï>"
+
+#: engines/advancedDetector.cpp:334
#, c-format
msgid "The game in '%s' seems to be unknown."
msgstr "³àÐ ã '%s' ÝÕÒöÔÞÜÐ."
-#: engines/advancedDetector.cpp:318
+#: engines/advancedDetector.cpp:335
msgid "Please, report the following data to the ScummVM team along with name"
msgstr "±ãÔì ÛÐáÚÐ, ßÕàÕÔÐÙâÕ ÝØÖçÕÝÐÒÕÔÕÝã öÝäÞàÜÐæöî ÚÞÜÐÝÔö ScummVM àÐ×ÞÜ ×"
-#: engines/advancedDetector.cpp:320
+#: engines/advancedDetector.cpp:337
msgid "of the game you tried to add and its version/language/etc.:"
msgstr "ÝÐ×ÒÞî ÓàØ, ïÚã ÒØ ÝÐÜÐÓÐôâÕáì ÔÞÔÐâØ, Ð âÐÚÞÖ ÷÷ ÒÕàáöî/ÜÞÒã/âÐ öÝèÕ:"
@@ -1388,11 +1442,11 @@ msgstr "ÝÐ×ÒÞî ÓàØ, ïÚã ÒØ ÝÐÜÐÓÐôâÕáì ÔÞÔÐâØ, Ð âÐÚÞÖ ÷÷ ÒÕàáöî/ÜÞÒã/âÐ öÝèÕ:"
msgid "~R~esume"
msgstr "¿àÞÔÞÒ~Ö~ØâØ"
-#: engines/dialogs.cpp:87
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
msgid "~L~oad"
msgstr "~·~ÐÒÐÝâÐÖØâØ"
-#: engines/dialogs.cpp:91
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
msgid "~S~ave"
msgstr "~·~ÐߨáÐâØ"
@@ -1417,15 +1471,15 @@ msgctxt "lowres"
msgid "~R~eturn to Launcher"
msgstr "~¿~ÞÒÕà.Ò ÓÞÛÞÒÝÕ ÜÕÝî"
-#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:764
-#: engines/avalanche/parser.cpp:1899 engines/cge/events.cpp:74
-#: engines/cge2/events.cpp:67 engines/cruise/menu.cpp:212
-#: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261
-#: engines/hugo/file.cpp:298 engines/neverhood/menumodule.cpp:877
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save game:"
msgstr "·ÑÕàÕÓâØ Óàã: "
@@ -1434,15 +1488,16 @@ msgstr "·ÑÕàÕÓâØ Óàã: "
#: backends/platform/wince/CEActionsPocket.cpp:267
#: backends/platform/wince/CEActionsSmartphone.cpp:45
#: backends/platform/wince/CEActionsSmartphone.cpp:231
-#: engines/agi/saveload.cpp:764 engines/avalanche/parser.cpp:1899
-#: engines/cge/events.cpp:74 engines/cge2/events.cpp:67
-#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336
-#: engines/dreamweb/saveload.cpp:261 engines/hugo/file.cpp:298
-#: engines/neverhood/menumodule.cpp:877 engines/parallaction/saveload.cpp:212
-#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:768
-#: engines/scumm/dialogs.cpp:188 engines/sherlock/scalpel/scalpel.cpp:1249
-#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:281
-#: engines/toon/toon.cpp:3338 engines/tsage/scenes.cpp:598
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
msgid "Save"
msgstr "·ÐߨáÐâØ"
@@ -1465,13 +1520,13 @@ msgstr ""
"·ÑÕàÕÖÕÝÝï áâÐÝã ÓàØ ÝÕ ÒÔÐÛÞáï (%s)!. ±ãÔì-ÛÐáÚÐ, ÔØÒöâìáï äÐÙÛ README ÔÛï "
"ÞáÝÞÒÝÞ÷ öÝÞàÜÐæö÷, Ð âÐÚÞÖ öÝáâàãÚæöÙ, ïÚ ÞâàØÜÐâØ ßÞÔÐÛìèã ÔÞßÞÜÞÓã."
-#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:109
-#: engines/mohawk/dialogs.cpp:170 engines/tsage/dialogs.cpp:106
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
msgid "~O~K"
msgstr "~O~K"
-#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:110
-#: engines/mohawk/dialogs.cpp:171 engines/tsage/dialogs.cpp:107
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
msgid "~C~ancel"
msgstr "²ö~Ô~ÜöÝÐ"
@@ -1479,23 +1534,23 @@ msgstr "²ö~Ô~ÜöÝÐ"
msgid "~K~eys"
msgstr "~º~ÛÐÒöèö"
-#: engines/engine.cpp:339
+#: engines/engine.cpp:342
msgid "Could not initialize color format."
msgstr "½Õ ÜÞÖã ÝÐÛÐèâãÒÐâØ äÞàÜÐâ ÚÞÛìÞàã."
-#: engines/engine.cpp:347
+#: engines/engine.cpp:350
msgid "Could not switch to video mode: '"
msgstr "½Õ ÒÔÐÛÞáï ßÕàÕÚÛîçØâØ ÒöÔÕÞàÕÖØÜ: '"
-#: engines/engine.cpp:356
+#: engines/engine.cpp:359
msgid "Could not apply aspect ratio setting."
msgstr "½Õ ÒÔÐÛÞáï ×ÐáâÞáãÒÐâØ ÚÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ."
-#: engines/engine.cpp:361
+#: engines/engine.cpp:364
msgid "Could not apply fullscreen setting."
msgstr "½Õ ÒÔÐÛÞáï ×ÐáâÞáãÒÐâØ ßÞÒÝÞÕÚàÐÝÝØÙ àÕÖØÜ."
-#: engines/engine.cpp:461
+#: engines/engine.cpp:464
msgid ""
"You appear to be playing this game directly\n"
"from the CD. This is known to cause problems,\n"
@@ -1509,7 +1564,7 @@ msgstr ""
"ÓàØ ÝÐ ÖÞàáâÚØÙ ÔØáÚ.\n"
"´ØÒöâìáï äÐÙÛ README ÔÛï ßÞÔÐÛìèØå öÝáâàãÚæöÙ."
-#: engines/engine.cpp:472
+#: engines/engine.cpp:475
msgid ""
"This game has audio tracks in its disk. These\n"
"tracks need to be ripped from the disk using\n"
@@ -1523,7 +1578,7 @@ msgstr ""
"âÞÓÞ, éÞÑ ÜÞÖÝÐ ÑãÛÞ áÛãåÐâØ ÜãרÚã ã Óàö.\n"
"´ØÒöâìáï äÐÙÛ README ÔÛï ßÞÔÐÛìèØå öÝáâàãÚæöÙ."
-#: engines/engine.cpp:530
+#: engines/engine.cpp:533
#, c-format
msgid ""
"Gamestate load failed (%s)! Please consult the README for basic information, "
@@ -1532,7 +1587,7 @@ msgstr ""
"·ÐÒÐÝâÐÖÕÝÝï áâÐÝã ÓàØ ÝÕ ÒÔÐÛÞáï (%s)! . ±ãÔì-ÛÐáÚÐ, ÔØÒöâìáï äÐÙÛ README "
"ÔÛï ÞáÝÞÒÝÞ÷ öÝÞàÜÐæö÷, Ð âÐÚÞÖ öÝáâàãÚæöÙ, ïÚ ÞâàØÜÐâØ ßÞÔÐÛìèã ÔÞßÞÜÞÓã."
-#: engines/engine.cpp:543
+#: engines/engine.cpp:546
msgid ""
"WARNING: The game you are about to start is not yet fully supported by "
"ScummVM. As such, it is likely to be unstable, and any saves you make might "
@@ -1542,11 +1597,11 @@ msgstr ""
"ScummVM. ÁÚÞàèÕ ×Ð ÒáÕ ÒÞÝÐ ÝÕ ÑãÔÕ ßàÐæîÒÐâØ áâÐÑöÛìÝÞ, ö ×ÑÕàÕÖÕÝÝï öÓÞà, "
"ïÚö ÒØ ×àÞÑØâÕ, ÜÞÖãâì ÝÕ ßàÐæîÒÐâØ ã ßÞÔÐÛìèØå ÒÕàáöïå ScummVM."
-#: engines/engine.cpp:546
+#: engines/engine.cpp:549
msgid "Start anyway"
msgstr "²áÕ ÞÔÝÞ ×ÐßãáâØâØ"
-#: audio/adlib.cpp:2291
+#: audio/adlib.cpp:2290
msgid "AdLib Emulator"
msgstr "µÜãÛïâÞà AdLib"
@@ -1627,11 +1682,11 @@ msgstr "°ãÔöÞ FM-Towns"
msgid "PC-98 Audio"
msgstr "°ãÔöÞ PC-98"
-#: audio/softsynth/mt32.cpp:200
+#: audio/softsynth/mt32.cpp:196
msgid "Initializing MT-32 Emulator"
msgstr "½ÐÛÐèâÞÒãî ÕÜãÛïâÞà MT-32"
-#: audio/softsynth/mt32.cpp:426
+#: audio/softsynth/mt32.cpp:434
msgid "MT-32 Emulator"
msgstr "µÜãÛïâÞà MT-32"
@@ -1663,7 +1718,7 @@ msgstr "²Ø ÔöÙáÝÞ åÞçÕâÕ ÒØÙâØ?"
#: backends/platform/symbian/src/SymbianActions.cpp:52
#: backends/platform/wince/CEActionsPocket.cpp:44
#: backends/platform/wince/CEActionsSmartphone.cpp:52
-#: engines/scumm/dialogs.cpp:192 engines/scumm/help.cpp:83
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
#: engines/scumm/help.cpp:85
msgid "Quit"
msgstr "²ØåöÔ"
@@ -1748,11 +1803,11 @@ msgstr "ÀÕÖØÜ áÐÜÞâïÓÝÕÝÝï ÒÚÛîçÕÝÞ"
msgid "Swipe three fingers to the right to toggle."
msgstr "¿àÞÒÕÔöâì âàìÞÜÐ ßÐÛìæïÜö ÝÐßàÐÒÞ ÔÛï ßÕàÕÚÛîçÕÝÝï."
-#: backends/graphics/opengl/opengl-graphics.cpp:119
+#: backends/graphics/opengl/opengl-graphics.cpp:126
msgid "OpenGL"
msgstr "OpenGL"
-#: backends/graphics/opengl/opengl-graphics.cpp:120
+#: backends/graphics/opengl/opengl-graphics.cpp:127
msgid "OpenGL (No filtering)"
msgstr "OpenGL (ÑÕ× äöÛìâàöÒ)"
@@ -1767,19 +1822,19 @@ msgctxt "lowres"
msgid "Normal (no scaling)"
msgstr "±Õ× ×ÑöÛìèÕÝÝï"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2215
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
msgid "Enabled aspect ratio correction"
msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ãÒöÜÚÝÕÝÞ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2221
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
msgid "Disabled aspect ratio correction"
msgstr "ºÞàÕÚæöî áßöÒÒöÔÝÞèÕÝÝï áâÞàöÝ ÒØÜÚÝÕÝÞ"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2276
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
msgid "Active graphics filter:"
msgstr "¿ÞâÞçÝØÙ ÓàÐäöçÝØÙ äöÛìâà:"
-#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2318
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
msgid "Windowed mode"
msgstr "²öÚÞÝÝØÙ àÕÖØÜ"
@@ -1812,7 +1867,7 @@ msgid "Windows MIDI"
msgstr "Windows MIDI"
#: backends/platform/ds/arm9/source/dsoptions.cpp:56
-#: engines/scumm/dialogs.cpp:291
+#: engines/scumm/dialogs.cpp:287
msgid "~C~lose"
msgstr "~·~ÐÚàØâØ"
@@ -2304,20 +2359,38 @@ msgstr ""
"½Õ ×ÐÑãÔìâÕ ßÕàÕßàØ×ÝÐçØâØ ÚÝÞßÚã ÔÛï Ôö÷ 'ÁåÞÒÐâØ ¿ÐÝÕÛì öÝáâà.' éÞÑ "
"ßÞÑÐçØâØ ÒÕáì öÝÒÕÝâÐà"
-#: backends/updates/macosx/macosx-updates.mm:67
+#: backends/updates/macosx/macosx-updates.mm:79
msgid "Check for Updates..."
-msgstr "¿ÕàÕÒöàïî ÞÝÞÒÛÕÝÝï..."
+msgstr "¿ÕàÕÒöàØâØ ÞÝÞÒÛÕÝÝï..."
+
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "ÀÕÖØÜ ÑÕ× ÚÞÛìÞàã"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "¿ÞÚÐ×ãÒÐâØ ÛöÝö÷ ÞÑ'ôÚâöÒ"
#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
-#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:47
-#: engines/neverhood/detection.cpp:160 engines/sci/detection.cpp:404
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
msgid "Use original save/load screens"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÞàØÓ. ×ÑÕàÕÖÕÝÝï/×ÐÒÐÝâÐÖÕÝÝï ÕÚàÐÝØ"
#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
-#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:48
-#: engines/neverhood/detection.cpp:161 engines/sci/detection.cpp:405
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
#: engines/toltecs/detection.cpp:201
msgid "Use the original save/load screens, instead of the ScummVM ones"
msgstr ""
@@ -2346,27 +2419,49 @@ msgstr ""
"²ÚÛîçÐô ßöÔâàØÜÚã ÜØèö. ´Þ×ÒÞÛïô ÒØÚÞàØáâÞÒãÒÐâØ ÜØèã ÔÛï ßÕàÕáãÒÐÝÝï âÐ "
"ãßàÐÒÛöÝÝï ÜÕÝî."
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/detection.cpp:177
+msgid "Use Hercules hires font"
+msgstr "²ØÚÞàØáâÞÒãÒÐâØ èàØäâ Hercules"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+"²ØÚÞàØáâÞÒãô èàØäâ ÒØáÞÚÞÓÞ àÞ×ÓÐÛãÖÕÝÝï Hercules, ïÚéÞ äÐÙÛ × èàØäâÞÜ ô "
+"ÔÞáãßÝØÙ"
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr "ÁâÐ񯉯 ÝÐ ßÐã×ã ßöÔ çÐá ÒÒÞÔã ÚÞÜÐÝÔ"
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+"¿ÞÚÐ×ãô ÒöÚÝÞ ÔÛï ÒÒÞÔã ÚÞÜÐÝÔØ âÐ áâÐÒØâì Óàã ÝÐ ßÐã×ã (ßÞÔöÑÝÞ ÔÞ SCI),"
+"×ÐÜöáâì ÑÕ×ßÞáÕàÕÔÝìÞÓÞ ÒÒÞÔã."
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore game:"
msgstr "²öÔÝÞ񯉯 Óàã:"
-#: engines/agi/saveload.cpp:777 engines/avalanche/parser.cpp:1887
-#: engines/cge/events.cpp:85 engines/cge2/events.cpp:78
-#: engines/drascula/saveload.cpp:349 engines/dreamweb/saveload.cpp:169
-#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:890
-#: engines/sci/engine/kfile.cpp:867 engines/sherlock/scalpel/scalpel.cpp:1262
-#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:256
-#: engines/toon/toon.cpp:3430
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
msgid "Restore"
msgstr "²öÔÝÞÒØâØ"
-#: engines/agos/saveload.cpp:160 engines/scumm/scumm.cpp:2377
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
#, c-format
msgid ""
"Failed to load game state from file:\n"
@@ -2377,7 +2472,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:195 engines/scumm/scumm.cpp:2370
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
#, c-format
msgid ""
"Failed to save game state to file:\n"
@@ -2388,7 +2483,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/saveload.cpp:203 engines/scumm/scumm.cpp:2388
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
#, c-format
msgid ""
"Successfully saved game state in file:\n"
@@ -2399,7 +2494,7 @@ msgstr ""
"\n"
"%s"
-#: engines/agos/animation.cpp:557
+#: engines/agos/animation.cpp:558
#, c-format
msgid "Cutscene file '%s' not found!"
msgstr "ÄÐÙÛ àÞÛØÚã '%s' ÝÕ ×ÝÐÙÔÕÝÞ!"
@@ -2429,20 +2524,20 @@ msgstr ""
"½ÐâØáÝöâì ¾º, éÞÑ ßÕàÕÒÕáâØ ÷å ×ÐàÐ×, öÝÐÚèÕ ãÕ ßÞÒöÔÞÜÛÕÝÝï ×'ïÒØâìáï ßàØ "
"ÝÐáâãßÝÞÜã ×ÐßãáÚã ÓàØ.\n"
-#: engines/dreamweb/detection.cpp:57
+#: engines/dreamweb/detection.cpp:58
msgid "Use bright palette mode"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ ïáÚàÐÒØÙ àÕÖØÜ ßÐÛöâàØ"
-#: engines/dreamweb/detection.cpp:58
+#: engines/dreamweb/detection.cpp:59
msgid "Display graphics using the game's bright palette"
msgstr "²öÔÞÑàÐÖÕÝÝï ÓàÐäöÚØ × ÒØÚÞàØáâÐÝÝïÜ ïáÚàÐÒÞ÷ ßÐÛöâàØ öÓà"
-#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1470
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
msgid "Failed to load game state from file."
msgstr "½Õ ÒÔÐÛÞáï ×ÐÒÐÝâÐÖØâØ áâÐÝ ÓàØ × äÐÙÛã."
-#: engines/gob/inter_v2.cpp:1540 engines/gob/inter_geisha.cpp:263
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
#: engines/tinsel/saveload.cpp:545
msgid "Failed to save game state to file."
msgstr "½Õ ÒÔÐÛÞáï ×ÑÕàÕÓâØ áâÐÝ ÓàØ ã äÐÙÛ."
@@ -2459,7 +2554,7 @@ msgstr "ÀÕÖØÜ èÒØÔÚÞÓÞ ÒöÔÕÞ"
msgid "Play movies at an increased speed"
msgstr "¿àÞÓàÐÒÐâØ ÒöÔÕÞ × ßöÔÒØéÕÝÝÞî èÒØÔÚöáâî"
-#: engines/groovie/script.cpp:408
+#: engines/groovie/script.cpp:407
msgid "Failed to save game"
msgstr "½Õ ÒÔÐÛÞáï ×ÐߨáÐâØ Óàã"
@@ -2633,49 +2728,57 @@ msgstr ""
"ÒöÔÚàØâØ ÚÞÝáÞÛì ÒöÔÛÐÔçØÚÐ ö ÒÒÕáâØ ÚÞÜÐÝÔã 'import_savefile'.\n"
"\n"
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr "¿ÞÚÐ×ãÒÐâØ àÞÛöÚ ßÞÛìÞâã ÝÐÔ Myst"
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr "ÀÞÛöÚ ßÞÛìÞâã ÝÐÔ Myst ÝÕ ßÞÚÐ×ãÒÐÒáï ÞàØÓöÝÐÛìÝØÜ ÔÒØÖÚÞÜ"
+
#. I18N: Option for fast scene switching
-#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
msgid "~Z~ip Mode Activated"
msgstr "ÀÕÖØÜ èÒØÔÚÞÓÞ ßÕàÕåÞÔã ÐÚâØÒÞÒÐÝÞ"
-#: engines/mohawk/dialogs.cpp:93
+#: engines/mohawk/dialogs.cpp:179
msgid "~T~ransitions Enabled"
msgstr "¿ÕàÕåÞÔØ ÐÚâØÒÞÒÐÝÞ"
#. I18N: Drop book page
-#: engines/mohawk/dialogs.cpp:95
+#: engines/mohawk/dialogs.cpp:181
msgid "~D~rop Page"
msgstr "²ØÚØÝãâØ áâÞàöÝÚã"
-#: engines/mohawk/dialogs.cpp:99
-msgid "~S~how Map"
+#: engines/mohawk/dialogs.cpp:185
+msgid "Show ~M~ap"
msgstr "¿ÞÚÐ×ÐâØ ÜÐßã"
-#: engines/mohawk/dialogs.cpp:105
-msgid "~M~ain Menu"
+#: engines/mohawk/dialogs.cpp:191
+msgid "Main Men~u~"
msgstr "³ÞÛÞÒÝÕ ÜÕÝî"
-#: engines/mohawk/dialogs.cpp:168
+#: engines/mohawk/dialogs.cpp:265
msgid "~W~ater Effect Enabled"
msgstr "µäÕÚâØ ÒÞÔØ ãÒöÜÚÝÕÝÞ"
-#: engines/neverhood/detection.cpp:167
+#: engines/neverhood/detection.cpp:184
msgid "Skip the Hall of Records storyboard scenes"
msgstr "¿ÕàÕáÚÐÚãÒÐâØ ·ÐÛã ÀÕÚÞàÔöÒ"
-#: engines/neverhood/detection.cpp:168
+#: engines/neverhood/detection.cpp:185
msgid "Allows the player to skip past the Hall of Records storyboard scenes"
msgstr "´Þ×ÒÞÛïô ÓàÐÒæÕÒö ßÕàÕáÚÐÚãÒÐâØ çÕàÕ× áæÕÝØ ã ·ÐÛö ÀÕÚÞàÔöÒ"
-#: engines/neverhood/detection.cpp:174
+#: engines/neverhood/detection.cpp:191
msgid "Scale the making of videos to full screen"
msgstr "ÀÞ×âïÓãÒÐâØ ÒöÔÕÞ ßàÞ áâÒÞàÕÝÝï öÓàØ"
-#: engines/neverhood/detection.cpp:175
+#: engines/neverhood/detection.cpp:192
msgid "Scale the making of videos, so that they use the whole screen"
msgstr "ÀÞ×âïÓãÒÐâØ ÒöÔÕÞ ßàÞ áâÒÞàÕÝÝï öÓàØ âÐÚ, éÞ ÒÞÝÞ ×ÐÙÜÐâØÜÕ ÒÕáì ÕÚàÐÝ"
-#: engines/parallaction/saveload.cpp:133
+#: engines/parallaction/saveload.cpp:130
#, c-format
msgid ""
"Can't save game in slot %i\n"
@@ -2684,23 +2787,23 @@ msgstr ""
"½Õ ÜÞÖã ×ÑÕàÕÓâØ Óàã ã áÛÞâ %i\n"
"\n"
-#: engines/parallaction/saveload.cpp:197
+#: engines/parallaction/saveload.cpp:194
msgid "Load file"
msgstr "·ÐÒÐÝâÐÖØâØ äÐÙÛ"
-#: engines/parallaction/saveload.cpp:204
+#: engines/parallaction/saveload.cpp:201
msgid "Loading game..."
msgstr "·ÐÒÐÝâÐÖãî Óàã..."
-#: engines/parallaction/saveload.cpp:212
+#: engines/parallaction/saveload.cpp:209
msgid "Save file"
msgstr "·ÑÕàÕÓâØ äÐÙÛ"
-#: engines/parallaction/saveload.cpp:219
+#: engines/parallaction/saveload.cpp:216
msgid "Saving game..."
msgstr "·ÑÕàÕÖãî Óàã..."
-#: engines/parallaction/saveload.cpp:272
+#: engines/parallaction/saveload.cpp:269
msgid ""
"ScummVM found that you have old savefiles for Nippon Safes that should be "
"renamed.\n"
@@ -2716,11 +2819,11 @@ msgstr ""
"½ÐâØáÝöâì ¾º, éÞÑ ßÕàÕÒÕáâØ ÷å ×ÐàÐ×, öÝÐÚèÕ ãÕ ßÞÒöÔÞÜÛÕÝÝï ×'ïÒØâìáï ßàØ "
"ÝÐáâãßÝÞÜã ×ÐßãáÚã ÓàØ.\n"
-#: engines/parallaction/saveload.cpp:319
+#: engines/parallaction/saveload.cpp:316
msgid "ScummVM successfully converted all your savefiles."
msgstr "ScummVM ãáßöèÝÞ ßÕàÕÒöÒ ãáö ²Ðèö ×ÑÕàÕÖÕÝÝï."
-#: engines/parallaction/saveload.cpp:321
+#: engines/parallaction/saveload.cpp:318
msgid ""
"ScummVM printed some warnings in your console window and can't guarantee all "
"your files have been converted.\n"
@@ -2776,37 +2879,45 @@ msgstr "°ÛâÕàÝÐâØÒÝØÙ Òáâãß"
msgid "Use an alternative game intro (CD version only)"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ ÐÛìâÕàÝÐâØÒÝØÙ Òáâãß ÓàØ (âöÛìÚØ CD ÒÕàáöï)"
-#: engines/sci/detection.cpp:374
+#: engines/sci/detection.cpp:384
msgid "Skip EGA dithering pass (full color backgrounds)"
msgstr "½Õ àÞÑØâØ àÐáâàãÒÐÝÝï EGA (äÞÝØ ã ßÞÒÝÞÜã ÚÞÛìÞàö)"
-#: engines/sci/detection.cpp:375
+#: engines/sci/detection.cpp:385
msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
msgstr ""
"½Õ àÞÑØâØ ÚàÞÚ àÐáâàãÒÐÝÝï ã öÓàÐå EGA, ÓàÐäöÚã ÑãÔÕ ßÞÚÐ×ÐÝÞ ã ßÞÒÝÞÜã "
"ÚÞÛìÞàö"
-#: engines/sci/detection.cpp:384
+#: engines/sci/detection.cpp:394
msgid "Enable high resolution graphics"
msgstr "ÃÒöÜÚÝãâØ ÓàÐäöÚã ÒØáÞÚÞÓÞ àÞ×ÓÐÛãÖÕÝÝï"
-#: engines/sci/detection.cpp:385
+#: engines/sci/detection.cpp:395
msgid "Enable high resolution graphics/content"
msgstr "ÃÒöÜÚÝãâØ ÓàÐäöÚã âÐ ÚÞÝâÕÝâ ã ÒØáÞÚÞÜã àÞ×ÓÐÛãÖÕÝÝö"
-#: engines/sci/detection.cpp:394
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr ""
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
msgid "Prefer digital sound effects"
msgstr "½ÐÔÐÒÐâØ ßÕàÕÒÐÓã æØäàÞÒØÜ ×ÒãÚÞÒØÜ ÕäÕÚâÐÜ"
-#: engines/sci/detection.cpp:395
+#: engines/sci/detection.cpp:415
msgid "Prefer digital sound effects instead of synthesized ones"
msgstr "²öÔÔÐÒÐâØ ßÕàÕÒÐÓã æØäàÞÒØÜ ×ÒãÚÞÒØÜ ÕäÕÚâÐÜ, Ð ÝÕ áØÝâÕ×ÞÒÐÝØÜ"
-#: engines/sci/detection.cpp:414
+#: engines/sci/detection.cpp:434
msgid "Use IMF/Yamaha FB-01 for MIDI output"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ IMF/Yahama FB-01 ÔÛï MIDI ÒØåÞÔã"
-#: engines/sci/detection.cpp:415
+#: engines/sci/detection.cpp:435
msgid ""
"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
"output"
@@ -2814,147 +2925,155 @@ msgstr ""
"²ØÚÞàØáâÞÒãÒÐâØ ÔÛïÒ ÒØÒÞÔã MIDI àÕÖØÜ ÚÐàâØ IBM Feature ÐÑÞ FM áöÝâÕ× "
"Yamaha FB-01"
-#: engines/sci/detection.cpp:425
+#: engines/sci/detection.cpp:445
msgid "Use CD audio"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ CD ÐãÔöÞ"
-#: engines/sci/detection.cpp:426
+#: engines/sci/detection.cpp:446
msgid "Use CD audio instead of in-game audio, if available"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ CD ÐãÔöÞ ×ÐÜöáâì ã-Óàö ÐãÔöÞ, ïÚéÞ âÐÚö ô"
-#: engines/sci/detection.cpp:436
+#: engines/sci/detection.cpp:456
msgid "Use Windows cursors"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ Windows ÚãàáÞàØ"
-#: engines/sci/detection.cpp:437
+#: engines/sci/detection.cpp:457
msgid ""
"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ Windows ÚãàáÞàØ (ÜÕÝèØå ö ÜÞÝÞåàÞÜÝØå), ×ÐÜöáâì DOS"
-#: engines/sci/detection.cpp:447
+#: engines/sci/detection.cpp:467
msgid "Use silver cursors"
msgstr "²ØÚÞàØáâÞÒãÒÐâØ áàöÑÝö ÚãàáÞàØ"
-#: engines/sci/detection.cpp:448
+#: engines/sci/detection.cpp:468
msgid ""
"Use the alternate set of silver cursors, instead of the normal golden ones"
msgstr ""
"²ØÚÞàØáâÞÒãÒÐâØ ÐÛìâÕàÝÐâØÒÝØÙ ÝÐÑöà áàöÑÝØå ÚãàáÞàöÒ, ×ÐÜöáâì ×ÒØçÐÙÝØå "
"×ÞÛÞâØå"
-#: engines/scumm/dialogs.cpp:176
+#: engines/scumm/detection.cpp:1340
+msgid "Show Object Line"
+msgstr "¿ÞÚÐ×ãÒÐâØ ÛöÝö÷ ÞÑ'ôÚâöÒ"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr "¿ÞÚÐ×ãÒÐâØ ÝÐ×ÒØ ÞÑ'ôÚâØÒ ÒÝØ×ã ÕÚàÐÝã"
+
+#: engines/scumm/dialogs.cpp:172
#, c-format
msgid "Insert Disk %c and Press Button to Continue."
msgstr "²áâÐÒâÕ ÔØáÚ %c âÐ ÝÐâØáÝöâì ÚÛÐÒöèã ÔÛï ßàÞÔÞÒÖÕÝÝï."
-#: engines/scumm/dialogs.cpp:177
+#: engines/scumm/dialogs.cpp:173
#, c-format
msgid "Unable to Find %s, (%c%d) Press Button."
msgstr "½Õ ÒÔÐÛÞáï ×ÝÐÙâØ %s, (%c%d) ½ÐâØáÝöâì ÚÛÐÒöèã."
-#: engines/scumm/dialogs.cpp:178
+#: engines/scumm/dialogs.cpp:174
#, c-format
msgid "Error reading disk %c, (%c%d) Press Button."
msgstr "¿ÞÜØÛÚÐ çØâÐÝÝï ÔØáÚã %c, (%c%d) ½ÐâØáÝöâì ÚÛÐÒöèã."
-#: engines/scumm/dialogs.cpp:179
+#: engines/scumm/dialogs.cpp:175
msgid "Game Paused. Press SPACE to Continue."
msgstr "¦Óàã ßàØ×ãߨÝÕÝÞ. ½ÐâØáÝöâì ßàÞÑöÛ ÔÛï ßàÞÔÞÒÖÕÝÝï."
#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
#. "Moechten Sie wirklich neu starten? (J/N)J"
#. Will react to J as 'Yes'
-#: engines/scumm/dialogs.cpp:183
+#: engines/scumm/dialogs.cpp:179
msgid "Are you sure you want to restart? (Y/N)Y"
msgstr "²Ø ãßÕÒÝÕÝö, éÞ åÞçÕâÕ àÞ×ßÞçÐâØ áßÞçÐâÚã? (Y/N)Y"
#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
-#: engines/scumm/dialogs.cpp:185
+#: engines/scumm/dialogs.cpp:181
msgid "Are you sure you want to quit? (Y/N)Y"
msgstr "²Ø ãßÕÒÝÕÝö, éÞ åÞçÕâÕ ÒØÙâØ? (Y/N)Y"
-#: engines/scumm/dialogs.cpp:190
+#: engines/scumm/dialogs.cpp:186
msgid "Play"
msgstr "³àÐâØ"
-#: engines/scumm/dialogs.cpp:194
+#: engines/scumm/dialogs.cpp:190
msgid "Insert save/load game disk"
msgstr "²áâÐÒâÕ ÔØáÚ ×ö ×ÑÕàÕÖÕÝÝïÜ öÓÞà"
-#: engines/scumm/dialogs.cpp:195
+#: engines/scumm/dialogs.cpp:191
msgid "You must enter a name"
msgstr "²Ø ÜãáØâÕ ÒÒÕáâØ öÜ'ï"
-#: engines/scumm/dialogs.cpp:196
+#: engines/scumm/dialogs.cpp:192
msgid "The game was NOT saved (disk full?)"
msgstr "³àã ½µ ±Ã»¾ ×ÐߨáÐÝÞ (ÔØáÚ ßÞÒÝØÙ?)"
-#: engines/scumm/dialogs.cpp:197
+#: engines/scumm/dialogs.cpp:193
msgid "The game was NOT loaded"
msgstr "³àã ½µ ±Ã»¾ ×ÐÒÐÝâÐÖÕÝÞ"
-#: engines/scumm/dialogs.cpp:198
+#: engines/scumm/dialogs.cpp:194
#, c-format
msgid "Saving '%s'"
msgstr "·Ðߨáãî '%s'"
-#: engines/scumm/dialogs.cpp:199
+#: engines/scumm/dialogs.cpp:195
#, c-format
msgid "Loading '%s'"
msgstr "·ÐÒÐÝâÐÖãî '%s'"
-#: engines/scumm/dialogs.cpp:200
+#: engines/scumm/dialogs.cpp:196
msgid "Name your SAVE game"
msgstr "½Ð×ÞÒöâì áÒÞô ×ÑÕàÕÖÕÝÝï öÓàØ"
-#: engines/scumm/dialogs.cpp:201
+#: engines/scumm/dialogs.cpp:197
msgid "Select a game to LOAD"
msgstr "²ØÑÕàöâì Óàã ÔÛï ×ÐÒÐÝâÐÖÕÝÝï"
-#: engines/scumm/dialogs.cpp:202
+#: engines/scumm/dialogs.cpp:198
msgid "Game title)"
msgstr "½Ð×ÒÐ ÓàØ)"
#. I18N: Previous page button
-#: engines/scumm/dialogs.cpp:288
+#: engines/scumm/dialogs.cpp:284
msgid "~P~revious"
msgstr "~¿~ÞßÕà"
#. I18N: Next page button
-#: engines/scumm/dialogs.cpp:290
+#: engines/scumm/dialogs.cpp:286
msgid "~N~ext"
msgstr "~½~Ðáâ"
-#: engines/scumm/dialogs.cpp:602
+#: engines/scumm/dialogs.cpp:598
msgid "Speech Only"
msgstr "ÂöÛìÚØ Þ×ÒãçÚÐ"
-#: engines/scumm/dialogs.cpp:603
+#: engines/scumm/dialogs.cpp:599
msgid "Speech and Subtitles"
msgstr "¾×ÒãçÚÐ âÐ áãÑâØâàØ"
-#: engines/scumm/dialogs.cpp:604
+#: engines/scumm/dialogs.cpp:600
msgid "Subtitles Only"
msgstr "ÂöÛìÚØ áãÑâØâàØ"
-#: engines/scumm/dialogs.cpp:612
+#: engines/scumm/dialogs.cpp:608
msgctxt "lowres"
msgid "Speech & Subs"
msgstr "¾×ÒãçÚÐ âÐ âÕÚáâ"
-#: engines/scumm/dialogs.cpp:658
+#: engines/scumm/dialogs.cpp:654
msgid "Select a Proficiency Level."
msgstr "¾ÑÕàöâì àÕÖØÜ áÚÛÐÔÝÞáâö."
-#: engines/scumm/dialogs.cpp:660
+#: engines/scumm/dialogs.cpp:656
msgid "Refer to your Loom(TM) manual for help."
msgstr "·Ð ÔÞßÞÜÞÓÞî ×ÒÕàâÐÙâÕáï ÔÞ öÝáâàãÚæö÷ Loom(TM)."
-#: engines/scumm/dialogs.cpp:664
+#: engines/scumm/dialogs.cpp:660
msgid "Practice"
msgstr "¿àÐÚâØÚÐ"
-#: engines/scumm/dialogs.cpp:665
+#: engines/scumm/dialogs.cpp:661
msgid "Expert"
msgstr "µÚáßÕàâ"
@@ -3491,23 +3610,23 @@ msgstr "»ÕâöâØ ÝÐßàÐÒÞ"
msgid "Fly to lower right"
msgstr "»ÕâöâØ ÔÞÝØ×ã ÝÐßàÐÒÞ"
-#: engines/scumm/input.cpp:580
+#: engines/scumm/input.cpp:578
msgid "Snap scroll on"
msgstr "¿àÞÚàãâÚÐ áâàØÑÚÐÜØ"
-#: engines/scumm/input.cpp:582
+#: engines/scumm/input.cpp:580
msgid "Snap scroll off"
msgstr "²ÜØÚÐô ßàÞÚàãâÚã áâàØÑÚÐÜØ"
-#: engines/scumm/input.cpp:595
+#: engines/scumm/input.cpp:593
msgid "Music volume: "
msgstr "³ãçÝöáâì Üã×ØÚØ: "
-#: engines/scumm/input.cpp:612
+#: engines/scumm/input.cpp:610
msgid "Subtitle speed: "
msgstr "ÈÒØÔ. áãÑâØâàöÒ: "
-#: engines/scumm/scumm.cpp:1832
+#: engines/scumm/scumm.cpp:1850
#, c-format
msgid ""
"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
@@ -3516,7 +3635,7 @@ msgstr ""
"ÀÕÖØÜ \"àöÔÝÞÓÞ\" MIDI ßÞâàÕÑãô ßÞÝÞÒÛÕÝÝï Roland Upgrade ÒöÔ\n"
"LucasArts, ßàÞâÕ %s ÒöÔáãâÝöÙ. ¿ÕàÕÜØÚÐîáì ÝÐ AdLib."
-#: engines/scumm/scumm.cpp:2644
+#: engines/scumm/scumm.cpp:2666
msgid ""
"Usually, Maniac Mansion would start now. But for that to work, the game "
"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
@@ -3551,8 +3670,8 @@ msgid ""
"Files button in-game shows original savegame dialog rather than the ScummVM "
"menu"
msgstr ""
-"ºÝÞßÚÐ \"ÄÐÙÛØ\" ã Óàö ßÞÚÐ×ãÒÐâØÜÕ ÞàØÓöÝÐÛìÝØÙ ÕÚàÐÝ ×ÑÕàÕÖÕÝÝï "
-"×ÐÜöáâì ÜÕÝî ScummVM"
+"ºÝÞßÚÐ \"ÄÐÙÛØ\" ã Óàö ßÞÚÐ×ãÒÐâØÜÕ ÞàØÓöÝÐÛìÝØÙ ÕÚàÐÝ ×ÑÕàÕÖÕÝÝï ×ÐÜöáâì "
+"ÜÕÝî ScummVM"
#: engines/sherlock/detection.cpp:81
msgid "Pixellated scene transitions"
@@ -3571,8 +3690,8 @@ msgid ""
"Only show hotspot names after you actually click on a hotspot or action "
"button"
msgstr ""
-"¿ÞÚÐ×ãÒÐâØ ÝÐ×ÒØ æöÚÐÒØå âÞçÞÚ âöÛìÚØ ßöáÛï ÑÕ×ßÞáÕàÕÔÝìÞÓÞ ÚÛöÚã ßÞ ÝØÜ "
-"ÐÑÞ Ôö÷ × ÝØÜØ"
+"¿ÞÚÐ×ãÒÐâØ ÝÐ×ÒØ æöÚÐÒØå âÞçÞÚ âöÛìÚØ ßöáÛï ÑÕ×ßÞáÕàÕÔÝìÞÓÞ ÚÛöÚã ßÞ ÝØÜ ÐÑÞ "
+"Ôö÷ × ÝØÜØ"
#: engines/sherlock/detection.cpp:101
msgid "Show character portraits"
@@ -3694,13 +3813,24 @@ msgstr "¿ÞÚÐ×ãÒÐâØ ÜöâÚØ ÞÑ'ôÚâöÒ"
msgid "Show labels for objects on mouse hover"
msgstr "¿ÞÚÐ×ãÒÐâØ ÜöâÚØ ÔÛï ÞÑ'ôÚâöÒ ßàØ ÝÐÒÕÔÕÝÝö ÜØèö"
-#: engines/teenagent/resources.cpp:95
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr "²ØÚÞàØáâÞÒãÒÐâØ Þ×ÒãçÕÝÝï ÐÝÓÛöÙáìÚÞî"
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+"²ØÚÞàØáâÞÒãÒÐâØ Þ×ÒãçÕÝÝï ÐÝÓÛöÙáÚÞî ×ÐÜöáâì ÝöÜÕæìÚÞÓÞ ÔÛï Òáöå ÜÞÒ ÞÚàöÜ "
+"ÝöÜÕæìÚÞ÷"
+
+#: engines/teenagent/resources.cpp:96
msgid ""
"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
msgstr ""
"à ÒÐá ÒöÔáâãÝöÙ äÐÙÛ 'teenagent.dat'. ²ö×ìÜöâì ÙÞÓÞ ÝÐ ÒÕÑáÐÙâö ScummVM"
-#: engines/teenagent/resources.cpp:116
+#: engines/teenagent/resources.cpp:117
msgid ""
"The teenagent.dat file is compressed and zlib hasn't been included in this "
"executable. Please decompress it"
diff --git a/po/zh-Latn_CN.po b/po/zh-Latn_CN.po
new file mode 100644
index 0000000000..f8f3bb1d42
--- /dev/null
+++ b/po/zh-Latn_CN.po
@@ -0,0 +1,3856 @@
+# LANGUAGE translation for ScummVM.
+# Copyright (C) YEAR ScummVM Team
+# This file is distributed under the same license as the ScummVM package.
+# Chenbo Li <lichenbo1949@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ScummVM 1.9.0git\n"
+"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n"
+"POT-Creation-Date: 2016-07-19 09:07+0200\n"
+"PO-Revision-Date: 2016-03-15 04:09-0700\n"
+"Last-Translator: Chenbo Li <lichenbo1949@gmail.com>\n"
+"Language-Team: Chenbo Li <lichenbo1949@gmail.com>\n"
+"Language: Chinese Pinyin (Mandarin)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7\n"
+
+#: gui/about.cpp:94
+#, c-format
+msgid "(built on %s)"
+msgstr "(Bianyiyu %s)"
+
+#: gui/about.cpp:101
+msgid "Features compiled in:"
+msgstr "Gongneng BianyiYu"
+
+#: gui/about.cpp:110
+msgid "Available engines:"
+msgstr "KeyongDeYinQing"
+
+#: gui/browser.cpp:68 gui/browser_osx.mm:104
+msgid "Show hidden files"
+msgstr "Xianshi Yincang Wenjian"
+
+#: gui/browser.cpp:68
+msgid "Show files marked with the hidden attribute"
+msgstr "Xianshi Suoyou Yincang Shuxing Wenjian"
+
+#: gui/browser.cpp:72
+msgid "Go up"
+msgstr "ShangYiJi"
+
+#: gui/browser.cpp:72 gui/browser.cpp:74
+msgid "Go to previous directory level"
+msgstr "Fanhui Zhiqian Mulu"
+
+#: gui/browser.cpp:74
+msgctxt "lowres"
+msgid "Go up"
+msgstr "ShangYiJi"
+
+#: gui/browser.cpp:75 gui/chooser.cpp:46 gui/editrecorddialog.cpp:67
+#: gui/filebrowser-dialog.cpp:64 gui/fluidsynth-dialog.cpp:152
+#: gui/KeysDialog.cpp:43 gui/launcher.cpp:353 gui/massadd.cpp:95
+#: gui/options.cpp:1259 gui/predictivedialog.cpp:73 gui/recorderdialog.cpp:69
+#: gui/recorderdialog.cpp:155 gui/saveload-dialog.cpp:216
+#: gui/saveload-dialog.cpp:276 gui/saveload-dialog.cpp:547
+#: gui/saveload-dialog.cpp:931 gui/themebrowser.cpp:55
+#: gui/updates-dialog.cpp:113 engines/engine.cpp:549
+#: backends/events/default/default-events.cpp:196
+#: backends/events/default/default-events.cpp:218
+#: backends/platform/wii/options.cpp:48 engines/drascula/saveload.cpp:49
+#: engines/parallaction/saveload.cpp:271 engines/scumm/dialogs.cpp:187
+#: engines/sword1/control.cpp:865
+msgid "Cancel"
+msgstr "Quxiao"
+
+#: gui/browser.cpp:76 gui/browser_osx.mm:103 gui/chooser.cpp:47
+#: gui/filebrowser-dialog.cpp:65 gui/themebrowser.cpp:56
+msgid "Choose"
+msgstr "Xuanze"
+
+#: gui/editrecorddialog.cpp:58
+msgid "Author:"
+msgstr "Zuozhe:"
+
+#: gui/editrecorddialog.cpp:59 gui/launcher.cpp:204
+msgid "Name:"
+msgstr "Xingming:"
+
+#: gui/editrecorddialog.cpp:60
+msgid "Notes:"
+msgstr "Beizhu:"
+
+#: gui/editrecorddialog.cpp:68 gui/predictivedialog.cpp:74
+msgid "Ok"
+msgstr "Queding"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Choose file for loading"
+msgstr "Xuanze YaoJiazai de Wenjian"
+
+#: gui/filebrowser-dialog.cpp:49
+msgid "Enter filename for saving"
+msgstr "Shuru Baocun de Wenjianming"
+
+#: gui/filebrowser-dialog.cpp:132
+msgid "Do you really want to overwrite the file?"
+msgstr "Nin Shifou Queding Fugai Ciwenjian"
+
+#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+#: backends/platform/wince/CEActionsPocket.cpp:326
+#: backends/platform/wince/CEActionsSmartphone.cpp:287
+#: backends/platform/wince/CELauncherDialog.cpp:83
+#: engines/kyra/saveload_eob.cpp:557 engines/kyra/saveload_eob.cpp:590
+msgid "Yes"
+msgstr "Shi"
+
+#: gui/filebrowser-dialog.cpp:132 gui/fluidsynth-dialog.cpp:217
+#: gui/launcher.cpp:797 gui/launcher.cpp:945 gui/launcher.cpp:1004
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+#: backends/platform/wince/CEActionsPocket.cpp:326
+#: backends/platform/wince/CEActionsSmartphone.cpp:287
+#: backends/platform/wince/CELauncherDialog.cpp:83
+#: engines/kyra/saveload_eob.cpp:557 engines/kyra/saveload_eob.cpp:590
+msgid "No"
+msgstr "Fou"
+
+#: gui/fluidsynth-dialog.cpp:68
+msgid "Reverb"
+msgstr "Hunxiang"
+
+#: gui/fluidsynth-dialog.cpp:70 gui/fluidsynth-dialog.cpp:102
+msgid "Active"
+msgstr "Jihuo"
+
+#: gui/fluidsynth-dialog.cpp:72
+msgid "Room:"
+msgstr "Fangjian:"
+
+#: gui/fluidsynth-dialog.cpp:79
+msgid "Damp:"
+msgstr "Shiqi:"
+
+#: gui/fluidsynth-dialog.cpp:86
+msgid "Width:"
+msgstr "Kuandu:"
+
+#: gui/fluidsynth-dialog.cpp:93 gui/fluidsynth-dialog.cpp:111
+msgid "Level:"
+msgstr "Jibie:"
+
+#: gui/fluidsynth-dialog.cpp:100
+msgid "Chorus"
+msgstr "Hechang:"
+
+#: gui/fluidsynth-dialog.cpp:104
+msgid "N:"
+msgstr "N:"
+
+#: gui/fluidsynth-dialog.cpp:118
+msgid "Speed:"
+msgstr "Sudu:"
+
+#: gui/fluidsynth-dialog.cpp:125
+msgid "Depth:"
+msgstr "Shendu:"
+
+#: gui/fluidsynth-dialog.cpp:132
+msgid "Type:"
+msgstr "Leixing:"
+
+#: gui/fluidsynth-dialog.cpp:135
+msgid "Sine"
+msgstr "Zhengxian"
+
+#: gui/fluidsynth-dialog.cpp:136
+msgid "Triangle"
+msgstr "Sanjiaoxing"
+
+#: gui/fluidsynth-dialog.cpp:138 gui/options.cpp:1174
+msgid "Misc"
+msgstr "Zaxiang"
+
+#: gui/fluidsynth-dialog.cpp:140
+msgid "Interpolation:"
+msgstr "Chazhi:"
+
+#: gui/fluidsynth-dialog.cpp:143
+msgid "None (fastest)"
+msgstr "Wu (Zuikuai)"
+
+#: gui/fluidsynth-dialog.cpp:144
+msgid "Linear"
+msgstr "Xianxing"
+
+#: gui/fluidsynth-dialog.cpp:145
+msgid "Fourth-order"
+msgstr "DiSiXu"
+
+#: gui/fluidsynth-dialog.cpp:146
+msgid "Seventh-order"
+msgstr "DiQiXu"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset"
+msgstr "Chongzhi"
+
+#: gui/fluidsynth-dialog.cpp:150
+msgid "Reset all FluidSynth settings to their default values."
+msgstr "Chongzhi Suoyou de FluidSynth Shezhi"
+
+#: gui/fluidsynth-dialog.cpp:153 gui/KeysDialog.cpp:42 gui/launcher.cpp:354
+#: gui/launcher.cpp:1052 gui/launcher.cpp:1056 gui/massadd.cpp:92
+#: gui/options.cpp:1260 gui/saveload-dialog.cpp:932 engines/engine.cpp:468
+#: engines/engine.cpp:479 backends/platform/wii/options.cpp:47
+#: backends/platform/wince/CELauncherDialog.cpp:54
+#: engines/agos/animation.cpp:559 engines/drascula/saveload.cpp:49
+#: engines/groovie/script.cpp:407 engines/parallaction/saveload.cpp:271
+#: engines/scumm/dialogs.cpp:189 engines/scumm/scumm.cpp:1852
+#: engines/scumm/players/player_v3m.cpp:130
+#: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131
+#: engines/sky/compact.cpp:141 engines/sword1/animation.cpp:524
+#: engines/sword1/animation.cpp:545 engines/sword1/animation.cpp:561
+#: engines/sword1/animation.cpp:569 engines/sword1/control.cpp:865
+#: engines/sword1/logic.cpp:1633 engines/sword2/animation.cpp:425
+#: engines/sword2/animation.cpp:445 engines/sword2/animation.cpp:461
+#: engines/sword2/animation.cpp:471
+msgid "OK"
+msgstr "Queding"
+
+#: gui/fluidsynth-dialog.cpp:217
+msgid ""
+"Do you really want to reset all FluidSynth settings to their default values?"
+msgstr "Ni Shifou Yao Chongzhi Suoyou de FluidSynth Shezhi?"
+
+#: gui/gui-manager.cpp:119 backends/keymapper/remap-dialog.cpp:53
+#: engines/scumm/help.cpp:126 engines/scumm/help.cpp:141
+#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:192
+#: engines/scumm/help.cpp:210
+msgid "Close"
+msgstr "Guanbi"
+
+#: gui/gui-manager.cpp:122
+msgid "Mouse click"
+msgstr "Shubiao Danji"
+
+#: gui/gui-manager.cpp:126 base/main.cpp:328
+msgid "Display keyboard"
+msgstr "Xianshi Jianpan"
+
+#: gui/gui-manager.cpp:130 base/main.cpp:332
+msgid "Remap keys"
+msgstr "Yingshe Jianwei"
+
+#: gui/gui-manager.cpp:133 base/main.cpp:335 engines/scumm/help.cpp:87
+msgid "Toggle fullscreen"
+msgstr "Quanping Qiehuan"
+
+#: gui/KeysDialog.cpp:41
+msgid "Map"
+msgstr "Yingshe"
+
+#: gui/KeysDialog.cpp:49
+msgid "Select an action and click 'Map'"
+msgstr "Xuanze Yige Xingwei bing Danji ‘Yingshe’"
+
+#: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141
+#, c-format
+msgid "Associated key : %s"
+msgstr "Guanlian Anjian : %s"
+
+#: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143
+#, c-format
+msgid "Associated key : none"
+msgstr "Guanlian Anjian : Wu"
+
+#: gui/KeysDialog.cpp:90
+msgid "Please select an action"
+msgstr "Qing Xuanze Xingwei"
+
+#: gui/KeysDialog.cpp:106
+msgid "Press the key to associate"
+msgstr "Anxia Anjian lai Guanlian"
+
+#: gui/KeysDialog.cpp:145 gui/KeysDialog.h:36
+msgid "Choose an action to map"
+msgstr "Xuanze yao Yingshe de Xingwei"
+
+#: gui/launcher.cpp:193
+msgid "Game"
+msgstr "Youxi"
+
+#: gui/launcher.cpp:197
+msgid "ID:"
+msgstr "ID:"
+
+#: gui/launcher.cpp:197 gui/launcher.cpp:199 gui/launcher.cpp:200
+msgid ""
+"Short game identifier used for referring to saved games and running the game "
+"from the command line"
+msgstr ""
+"Yige Jianduan de Biaoshifu lai Baocun Youxi huo Cong Minglinghang zhong "
+"Yunxing"
+
+#: gui/launcher.cpp:199
+msgctxt "lowres"
+msgid "ID:"
+msgstr "ID:"
+
+#: gui/launcher.cpp:204 gui/launcher.cpp:206 gui/launcher.cpp:207
+msgid "Full title of the game"
+msgstr "Youxi Quanming"
+
+#: gui/launcher.cpp:206
+msgctxt "lowres"
+msgid "Name:"
+msgstr "Mingcheng:"
+
+#: gui/launcher.cpp:210
+msgid "Language:"
+msgstr "Yuyan:"
+
+#: gui/launcher.cpp:210 gui/launcher.cpp:211
+msgid ""
+"Language of the game. This will not turn your Spanish game version into "
+"English"
+msgstr ""
+"Youxi de Yuyan. CiXiang buhui jiang Yige XibanyaYu Banben Zhuancheng Yingwen"
+
+#: gui/launcher.cpp:212 gui/launcher.cpp:226 gui/options.cpp:89
+#: gui/options.cpp:741 gui/options.cpp:754 gui/options.cpp:1214
+#: audio/null.cpp:41
+msgid "<default>"
+msgstr "<Moren>"
+
+#: gui/launcher.cpp:222
+msgid "Platform:"
+msgstr "Pingtai:"
+
+#: gui/launcher.cpp:222 gui/launcher.cpp:224 gui/launcher.cpp:225
+msgid "Platform the game was originally designed for"
+msgstr "Youxi Chushi Yunxing de Pingtai:"
+
+#: gui/launcher.cpp:224
+msgctxt "lowres"
+msgid "Platform:"
+msgstr "Pingtai:"
+
+#: gui/launcher.cpp:237
+msgid "Engine"
+msgstr "Yinqing"
+
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
+msgid "Graphics"
+msgstr "Tuxiang"
+
+#: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090
+msgid "GFX"
+msgstr "GFX"
+
+#: gui/launcher.cpp:248
+msgid "Override global graphic settings"
+msgstr "Fugai Quanju Tuxiang Shezhi"
+
+#: gui/launcher.cpp:250
+msgctxt "lowres"
+msgid "Override global graphic settings"
+msgstr "Fugai Quanju Tuxiang Shezhi"
+
+#: gui/launcher.cpp:257 gui/options.cpp:1096
+msgid "Audio"
+msgstr "Yinpin"
+
+#: gui/launcher.cpp:260
+msgid "Override global audio settings"
+msgstr "Fugai Quanju Yinpin Shezhi"
+
+#: gui/launcher.cpp:262
+msgctxt "lowres"
+msgid "Override global audio settings"
+msgstr "Fugai QUanju Yinpin Shezhi"
+
+#: gui/launcher.cpp:271 gui/options.cpp:1101
+msgid "Volume"
+msgstr "Yinliang"
+
+#: gui/launcher.cpp:273 gui/options.cpp:1103
+msgctxt "lowres"
+msgid "Volume"
+msgstr "YinLiang"
+
+#: gui/launcher.cpp:276
+msgid "Override global volume settings"
+msgstr "Fugai Quanju YinLiang Shezhi"
+
+#: gui/launcher.cpp:278
+msgctxt "lowres"
+msgid "Override global volume settings"
+msgstr "Fugai Quanju YinLiang Shezhi"
+
+#: gui/launcher.cpp:287 gui/options.cpp:1111
+msgid "MIDI"
+msgstr "MIDI"
+
+#: gui/launcher.cpp:290
+msgid "Override global MIDI settings"
+msgstr "Fugai Quanju MIDI Shezhi"
+
+#: gui/launcher.cpp:292
+msgctxt "lowres"
+msgid "Override global MIDI settings"
+msgstr "Fugai Quanju MIDI Shezhi"
+
+#: gui/launcher.cpp:302 gui/options.cpp:1121
+msgid "MT-32"
+msgstr "MT-32"
+
+#: gui/launcher.cpp:305
+msgid "Override global MT-32 settings"
+msgstr "Fugai Quanju MT-32 Shezhi"
+
+#: gui/launcher.cpp:307
+msgctxt "lowres"
+msgid "Override global MT-32 settings"
+msgstr "Fugai Quanju MT-32 Shezhi"
+
+#: gui/launcher.cpp:316 gui/options.cpp:1128
+msgid "Paths"
+msgstr "Lujing"
+
+#: gui/launcher.cpp:318 gui/options.cpp:1130
+msgctxt "lowres"
+msgid "Paths"
+msgstr "Lujing"
+
+#: gui/launcher.cpp:325
+msgid "Game Path:"
+msgstr "Youxi Lujing:"
+
+#: gui/launcher.cpp:327
+msgctxt "lowres"
+msgid "Game Path:"
+msgstr "Youxi Lujing:"
+
+#: gui/launcher.cpp:332 gui/options.cpp:1154
+msgid "Extra Path:"
+msgstr "Qita Lujing:"
+
+#: gui/launcher.cpp:332 gui/launcher.cpp:334 gui/launcher.cpp:335
+msgid "Specifies path to additional data used by the game"
+msgstr "Zhiding Youxi Suoyong de Shuju de Cunfang Lujing"
+
+#: gui/launcher.cpp:334 gui/options.cpp:1156
+msgctxt "lowres"
+msgid "Extra Path:"
+msgstr "Qita Lujing:"
+
+#: gui/launcher.cpp:341 gui/options.cpp:1138
+msgid "Save Path:"
+msgstr "Baocun Lujing:"
+
+#: gui/launcher.cpp:341 gui/launcher.cpp:343 gui/launcher.cpp:344
+#: gui/options.cpp:1138 gui/options.cpp:1140 gui/options.cpp:1141
+msgid "Specifies where your saved games are put"
+msgstr "Zhiding Nin Jiang Youxi Baocun Zai le Nali"
+
+#: gui/launcher.cpp:343 gui/options.cpp:1140
+msgctxt "lowres"
+msgid "Save Path:"
+msgstr "Baocun Lujing:"
+
+#: gui/launcher.cpp:362 gui/launcher.cpp:461 gui/launcher.cpp:519
+#: gui/launcher.cpp:573 gui/options.cpp:1149 gui/options.cpp:1157
+#: gui/options.cpp:1166 gui/options.cpp:1297 gui/options.cpp:1303
+#: gui/options.cpp:1311 gui/options.cpp:1341 gui/options.cpp:1347
+#: gui/options.cpp:1354 gui/options.cpp:1460 gui/options.cpp:1463
+#: gui/options.cpp:1475
+msgctxt "path"
+msgid "None"
+msgstr "Wu"
+
+#: gui/launcher.cpp:367 gui/launcher.cpp:467 gui/launcher.cpp:577
+#: gui/options.cpp:1291 gui/options.cpp:1335 gui/options.cpp:1466
+#: backends/platform/wii/options.cpp:56
+msgid "Default"
+msgstr "Moren"
+
+#: gui/launcher.cpp:512 gui/options.cpp:1469
+msgid "Select SoundFont"
+msgstr "Xuanze SoundFont"
+
+#: gui/launcher.cpp:531 gui/launcher.cpp:684
+msgid "Select directory with game data"
+msgstr "Xuanze Youxi Shuju Mulu"
+
+#: gui/launcher.cpp:549
+msgid "Select additional game directory"
+msgstr "Xuanze Qita Youxi Mulu"
+
+#: gui/launcher.cpp:561 gui/options.cpp:1412
+msgid "Select directory for saved games"
+msgstr "Xuanze Youxi Baocun Mulu"
+
+#: gui/launcher.cpp:588
+msgid "This game ID is already taken. Please choose another one."
+msgstr "Ci Youxi ID Yi Bei Zhanyong. Qing Xuanze Qita Mingcheng"
+
+#: gui/launcher.cpp:628 engines/dialogs.cpp:111 engines/mohawk/dialogs.cpp:98
+msgid "~Q~uit"
+msgstr "~Q~Tuichu"
+
+#: gui/launcher.cpp:628 backends/platform/sdl/macosx/appmenu_osx.mm:106
+msgid "Quit ScummVM"
+msgstr "Tuichu ScummVM"
+
+#: gui/launcher.cpp:629
+msgid "A~b~out..."
+msgstr "~b~Guanyu"
+
+#: gui/launcher.cpp:629 backends/platform/sdl/macosx/appmenu_osx.mm:80
+msgid "About ScummVM"
+msgstr "Guanyu ScummVM"
+
+#: gui/launcher.cpp:630
+msgid "~O~ptions..."
+msgstr "~O~Xuanxiang"
+
+#: gui/launcher.cpp:630
+msgid "Change global ScummVM options"
+msgstr "Genggai ScummVM Quanju Shezhi"
+
+#: gui/launcher.cpp:632
+msgid "~S~tart"
+msgstr "~S~Kaishi"
+
+#: gui/launcher.cpp:632
+msgid "Start selected game"
+msgstr "Kaishi Xuanze de Youxi"
+
+#: gui/launcher.cpp:635
+msgid "~L~oad..."
+msgstr "~L~Jiazai"
+
+#: gui/launcher.cpp:635
+msgid "Load saved game for selected game"
+msgstr "Jiazai Xuanze Baocun de Youxi"
+
+#: gui/launcher.cpp:640
+msgid "~A~dd Game..."
+msgstr "~A~Tianjia Youxi ..."
+
+#: gui/launcher.cpp:640 gui/launcher.cpp:647
+msgid "Hold Shift for Mass Add"
+msgstr "Anzhu Shift Lai Piliang Tianjia"
+
+#: gui/launcher.cpp:642
+msgid "~E~dit Game..."
+msgstr "~E~Bianji Youxi ..."
+
+#: gui/launcher.cpp:642 gui/launcher.cpp:649
+msgid "Change game options"
+msgstr "Genggai Youxi Xuanxiang"
+
+#: gui/launcher.cpp:644
+msgid "~R~emove Game"
+msgstr "~R~Yichu Youxi"
+
+#: gui/launcher.cpp:644 gui/launcher.cpp:651
+msgid "Remove game from the list. The game data files stay intact"
+msgstr "Cong Liebiao zhong YIchu Youxi. Baoliu Youxi Shuju Wenjian"
+
+#: gui/launcher.cpp:647
+msgctxt "lowres"
+msgid "~A~dd Game..."
+msgstr "~A~Tianjia Youxi ..."
+
+#: gui/launcher.cpp:649
+msgctxt "lowres"
+msgid "~E~dit Game..."
+msgstr "~E~Bianji Youxi ..."
+
+#: gui/launcher.cpp:651
+msgctxt "lowres"
+msgid "~R~emove Game"
+msgstr "~R~Yichu Youxi ..."
+
+#: gui/launcher.cpp:659
+msgid "Search in game list"
+msgstr "Zai Youxi Liebiao zhong Sousuo"
+
+#: gui/launcher.cpp:663 gui/launcher.cpp:1226
+msgid "Search:"
+msgstr "Sousuo:"
+
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115 engines/cruise/menu.cpp:214
+#: engines/mohawk/dialogs.cpp:103 engines/mohawk/riven.cpp:726
+#: engines/pegasus/pegasus.cpp:353 engines/tsage/scenes.cpp:601
+msgid "Load game:"
+msgstr "Jiazai Youxi:"
+
+#: gui/launcher.cpp:687 engines/dialogs.cpp:115
+#: backends/platform/wince/CEActionsPocket.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:231
+#: engines/cruise/menu.cpp:214 engines/mohawk/dialogs.cpp:103
+#: engines/mohawk/riven.cpp:726 engines/parallaction/saveload.cpp:194
+#: engines/pegasus/pegasus.cpp:353 engines/scumm/dialogs.cpp:185
+#: engines/tsage/scenes.cpp:601
+msgid "Load"
+msgstr "Jiazai"
+
+#: gui/launcher.cpp:796
+msgid ""
+"Do you really want to run the mass game detector? This could potentially add "
+"a huge number of games."
+msgstr ""
+"Nin Queding yao Yunxing Youxi Piliang Jiance Ma? Zhe You Keneng Hui Zengjia "
+"Daliang Youxi."
+
+#: gui/launcher.cpp:845
+msgid "ScummVM couldn't open the specified directory!"
+msgstr "ScummVM Wufa Dakai Zhiding Mulu!"
+
+#: gui/launcher.cpp:857
+msgid "ScummVM could not find any game in the specified directory!"
+msgstr "ScummVM zai Zhiding Mulu Zhong Wufa Zhaodao Renhe Youxi!"
+
+#: gui/launcher.cpp:871
+msgid "Pick the game:"
+msgstr "Xuanze Youxi:"
+
+#: gui/launcher.cpp:945
+msgid "Do you really want to remove this game configuration?"
+msgstr "Nin Zhende Xiangyao Yichu Zhege Youxi Peizhi?"
+
+#: gui/launcher.cpp:1003
+msgid "Do you want to load saved game?"
+msgstr "Nin Yao Zairu Baocun de Youxi ma?"
+
+#: gui/launcher.cpp:1052
+msgid "This game does not support loading games from the launcher."
+msgstr "Ci Youxi Bu Zhichi cong Jiazaiqi Zhong Jiazai Youxi."
+
+#: gui/launcher.cpp:1056
+msgid "ScummVM could not find any engine capable of running the selected game!"
+msgstr "ScummVM Wufa Zhaodao Keyi Yunxing Ci Youxi de Yinqing!"
+
+#: gui/launcher.cpp:1163
+msgid "Mass Add..."
+msgstr "PiLiang Zengjia ..."
+
+#: gui/launcher.cpp:1165
+msgid "Record..."
+msgstr "Luxiang ..."
+
+#: gui/massadd.cpp:79 gui/massadd.cpp:82
+msgid "... progress ..."
+msgstr "... Jindu ..."
+
+#: gui/massadd.cpp:259
+msgid "Scan complete!"
+msgstr "Saomiao Wancheng!"
+
+#: gui/massadd.cpp:262
+#, c-format
+msgid "Discovered %d new games, ignored %d previously added games."
+msgstr "Faxian le %d ge Xinyouxi, Hulue %d ge YiTianjia de Youxi"
+
+#: gui/massadd.cpp:266
+#, c-format
+msgid "Scanned %d directories ..."
+msgstr "YiSaomiao %d ge Mulu ..."
+
+#: gui/massadd.cpp:269
+#, c-format
+msgid "Discovered %d new games, ignored %d previously added games ..."
+msgstr "Faxian le %d ge Xinyouxi, Hulue %d ge YiTianjia de Youxi ..."
+
+#: gui/onscreendialog.cpp:101 gui/onscreendialog.cpp:103
+msgid "Stop"
+msgstr "Tingzhi"
+
+#: gui/onscreendialog.cpp:106
+msgid "Edit record description"
+msgstr "Bianji Luxiang Shuoming"
+
+#: gui/onscreendialog.cpp:108
+msgid "Switch to Game"
+msgstr "Qiehuan zhi Youxi"
+
+#: gui/onscreendialog.cpp:110
+msgid "Fast replay"
+msgstr "Kuaisu Huitui"
+
+#: gui/options.cpp:87 common/updates.cpp:56
+msgid "Never"
+msgstr "Yongbu"
+
+#: gui/options.cpp:87
+msgid "every 5 mins"
+msgstr "Mei 5 Fenzhong"
+
+#: gui/options.cpp:87
+msgid "every 10 mins"
+msgstr "Mei 10 Fenzhong"
+
+#: gui/options.cpp:87
+msgid "every 15 mins"
+msgstr "Mei 15 Fenzhong"
+
+#: gui/options.cpp:87
+msgid "every 30 mins"
+msgstr "Mei 30 Fenzhong"
+
+#: gui/options.cpp:89
+msgid "8 kHz"
+msgstr "8 kHz"
+
+#: gui/options.cpp:89
+msgid "11 kHz"
+msgstr "11 kHz"
+
+#: gui/options.cpp:89
+msgid "22 kHz"
+msgstr "22 kHz"
+
+#: gui/options.cpp:89
+msgid "44 kHz"
+msgstr "44 kHz"
+
+#: gui/options.cpp:89
+msgid "48 kHz"
+msgstr "48 kHz"
+
+#: gui/options.cpp:261 gui/options.cpp:485 gui/options.cpp:586
+#: gui/options.cpp:655 gui/options.cpp:863
+msgctxt "soundfont"
+msgid "None"
+msgstr "Wu"
+
+#: gui/options.cpp:395
+msgid "Failed to apply some of the graphic options changes:"
+msgstr "Tuxing Xuanxiang Genggai Shibai:"
+
+#: gui/options.cpp:407
+msgid "the video mode could not be changed."
+msgstr "Shipin Moshi Wufa Genggai."
+
+#: gui/options.cpp:413
+msgid "the fullscreen setting could not be changed"
+msgstr "Quanping Shezhi Wufa Genggai"
+
+#: gui/options.cpp:419
+msgid "the aspect ratio setting could not be changed"
+msgstr "Bili Xuanxiang Wufa Genggai"
+
+#: gui/options.cpp:738
+msgid "Graphics mode:"
+msgstr "Tuxing Moshi:"
+
+#: gui/options.cpp:752
+msgid "Render mode:"
+msgstr "Xuanran Moshi:"
+
+#: gui/options.cpp:752 gui/options.cpp:753
+msgid "Special dithering modes supported by some games"
+msgstr "Youxi Zhichi Teshu de Doudong Moshi"
+
+#: gui/options.cpp:764
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2314
+msgid "Fullscreen mode"
+msgstr "Quanping Moshi"
+
+#: gui/options.cpp:767
+msgid "Aspect ratio correction"
+msgstr "Bili Jiaozheng"
+
+#: gui/options.cpp:767
+msgid "Correct aspect ratio for 320x200 games"
+msgstr "320x200 Youxi Bili Jiaozheng"
+
+#: gui/options.cpp:775
+msgid "Preferred Device:"
+msgstr "Youxian Shebei:"
+
+#: gui/options.cpp:775
+msgid "Music Device:"
+msgstr "Yinyue Shebei:"
+
+#: gui/options.cpp:775 gui/options.cpp:777
+msgid "Specifies preferred sound device or sound card emulator"
+msgstr "Zhiding Youxian Shengyin Shebei huo Shengka Moniqi"
+
+#: gui/options.cpp:775 gui/options.cpp:777 gui/options.cpp:778
+msgid "Specifies output sound device or sound card emulator"
+msgstr "Zhiding Shuchu Shengyin Shebei huo Shengka Moniqi"
+
+#: gui/options.cpp:777
+msgctxt "lowres"
+msgid "Preferred Dev.:"
+msgstr "Youxian Shebei:"
+
+#: gui/options.cpp:777
+msgctxt "lowres"
+msgid "Music Device:"
+msgstr "Yinyue Shebei:"
+
+#: gui/options.cpp:804
+msgid "AdLib emulator:"
+msgstr "AdLib Moniqi:"
+
+#: gui/options.cpp:804 gui/options.cpp:805
+msgid "AdLib is used for music in many games"
+msgstr "AdLib bei Henduo Youxi Yonglai Bofang Yinyue"
+
+#: gui/options.cpp:815
+msgid "Output rate:"
+msgstr "Shuchu Malv:"
+
+#: gui/options.cpp:815 gui/options.cpp:816
+msgid ""
+"Higher value specifies better sound quality but may be not supported by your "
+"soundcard"
+msgstr ""
+"Genggao de Shuxing Hui Tisheng Yinyue Zhiliang dan Youkeneng Nin de Shengka "
+"Buzhichi"
+
+#: gui/options.cpp:826
+msgid "GM Device:"
+msgstr "GM Shebei:"
+
+#: gui/options.cpp:826
+msgid "Specifies default sound device for General MIDI output"
+msgstr "Zhiding Tongyong MIDI Shuchu Moren Shengyin Shebei"
+
+#: gui/options.cpp:837
+msgid "Don't use General MIDI music"
+msgstr "Buyao Shiyong Tongyong MIDI Yinyue"
+
+#: gui/options.cpp:848 gui/options.cpp:910
+msgid "Use first available device"
+msgstr "Shiyong Diyige keyong de Shebei"
+
+#: gui/options.cpp:860
+msgid "SoundFont:"
+msgstr "SoundFont:"
+
+#: gui/options.cpp:860 gui/options.cpp:862 gui/options.cpp:863
+msgid "SoundFont is supported by some audio cards, FluidSynth and Timidity"
+msgstr "Yixie Shengka Zhichi SoundFont, Biru FluidSynth He Timidity"
+
+#: gui/options.cpp:862
+msgctxt "lowres"
+msgid "SoundFont:"
+msgstr "SoundFont:"
+
+#: gui/options.cpp:868
+msgid "Mixed AdLib/MIDI mode"
+msgstr "Hunhe AdLib/MIDI Moshi"
+
+#: gui/options.cpp:868
+msgid "Use both MIDI and AdLib sound generation"
+msgstr "TongShi Shiyong MIDI He AdLib Shengyin Shengcheng"
+
+#: gui/options.cpp:871
+msgid "MIDI gain:"
+msgstr "MIDI gain:"
+
+#: gui/options.cpp:881
+msgid "MT-32 Device:"
+msgstr "MT-32 Shebei:"
+
+#: gui/options.cpp:881
+msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"
+msgstr ""
+"QIng Zhiding Yongyu Roland MT-32/LAPC1/CM32I/CM64 Shuchu de Moren Shengyin "
+"Shebei"
+
+#: gui/options.cpp:886
+msgid "True Roland MT-32 (disable GM emulation)"
+msgstr "Zhen Roland MT-32 (Jinyong GM Moni)"
+
+#: gui/options.cpp:886 gui/options.cpp:888
+msgid ""
+"Check if you want to use your real hardware Roland-compatible sound device "
+"connected to your computer"
+msgstr ""
+"Jiancha Shifou Nin Xiang Shiyong Lianjie Dao Jisuanji de Zhenshi de Yingjian "
+"Roland Jianrong Shengyin Shebei"
+
+#: gui/options.cpp:888
+msgctxt "lowres"
+msgid "True Roland MT-32 (no GM emulation)"
+msgstr "Zhen Roland MT-32 Shebei (Wu GM Moni)"
+
+#: gui/options.cpp:891
+msgid "Roland GS Device (enable MT-32 mappings)"
+msgstr "Roland GS Shebei (Qiyong MT-32 Yingshe)"
+
+#: gui/options.cpp:891
+msgid ""
+"Check if you want to enable patch mappings to emulate an MT-32 on a Roland "
+"GS device"
+msgstr ""
+"Jiancha Shifou Nin Xiang Qiyong patch Yingshe Lai Zai Roland GS Shebei "
+"Shangmian Moni MT-32"
+
+#: gui/options.cpp:900
+msgid "Don't use Roland MT-32 music"
+msgstr "Buyao Shiyong Roland MT-32 Yinyue"
+
+#: gui/options.cpp:927
+msgid "Text and Speech:"
+msgstr "Wenzi he Yuyin:"
+
+#: gui/options.cpp:931 gui/options.cpp:941
+msgid "Speech"
+msgstr "Yuyin"
+
+#: gui/options.cpp:932 gui/options.cpp:942
+msgid "Subtitles"
+msgstr "Zimu"
+
+#: gui/options.cpp:933
+msgid "Both"
+msgstr "Liangzhe"
+
+#: gui/options.cpp:935
+msgid "Subtitle speed:"
+msgstr "Zimu Sudu:"
+
+#: gui/options.cpp:937
+msgctxt "lowres"
+msgid "Text and Speech:"
+msgstr "Wenben he Yuyin:"
+
+#: gui/options.cpp:941
+msgid "Spch"
+msgstr "Zimu"
+
+#: gui/options.cpp:942
+msgid "Subs"
+msgstr "Yuyin"
+
+#: gui/options.cpp:943
+msgctxt "lowres"
+msgid "Both"
+msgstr "Dou"
+
+#: gui/options.cpp:943
+msgid "Show subtitles and play speech"
+msgstr "Xianshi Zimu Bing Bofang Yuyin"
+
+#: gui/options.cpp:945
+msgctxt "lowres"
+msgid "Subtitle speed:"
+msgstr "Zimu Sudu"
+
+#: gui/options.cpp:961
+msgid "Music volume:"
+msgstr "Yinyue Yinliang:"
+
+#: gui/options.cpp:963
+msgctxt "lowres"
+msgid "Music volume:"
+msgstr "Yinyue Yinliang:"
+
+#: gui/options.cpp:970
+msgid "Mute All"
+msgstr "Quanbu Jinyin"
+
+#: gui/options.cpp:973
+msgid "SFX volume:"
+msgstr "Yinxiao Yinliang:"
+
+#: gui/options.cpp:973 gui/options.cpp:975 gui/options.cpp:976
+msgid "Special sound effects volume"
+msgstr "Texiao Yinliang"
+
+#: gui/options.cpp:975
+msgctxt "lowres"
+msgid "SFX volume:"
+msgstr "Yinxiao Yinliang:"
+
+#: gui/options.cpp:983
+msgid "Speech volume:"
+msgstr "Yuyin Yinliang:"
+
+#: gui/options.cpp:985
+msgctxt "lowres"
+msgid "Speech volume:"
+msgstr "Yuyin Yinliang:"
+
+#: gui/options.cpp:1115
+msgid "FluidSynth Settings"
+msgstr "FluidSynth Xuanxiang"
+
+#: gui/options.cpp:1146
+msgid "Theme Path:"
+msgstr "Zhuti Lujing:"
+
+#: gui/options.cpp:1148
+msgctxt "lowres"
+msgid "Theme Path:"
+msgstr "Zhuti Lujing:"
+
+#: gui/options.cpp:1154 gui/options.cpp:1156 gui/options.cpp:1157
+msgid "Specifies path to additional data used by all games or ScummVM"
+msgstr "Zhiding Suoyou Youxi huo ScummVM de Shuju Lujing"
+
+#: gui/options.cpp:1163
+msgid "Plugins Path:"
+msgstr "Chajian Lujing:"
+
+#: gui/options.cpp:1165
+msgctxt "lowres"
+msgid "Plugins Path:"
+msgstr "Chajian Lujing:"
+
+#: gui/options.cpp:1176
+msgctxt "lowres"
+msgid "Misc"
+msgstr "Zaxiang"
+
+#: gui/options.cpp:1178
+msgid "Theme:"
+msgstr "Zhuti:"
+
+#: gui/options.cpp:1182
+msgid "GUI Renderer:"
+msgstr "Jiemian Xuanran:"
+
+#: gui/options.cpp:1194
+msgid "Autosave:"
+msgstr "Zidong Baocun:"
+
+#: gui/options.cpp:1196
+msgctxt "lowres"
+msgid "Autosave:"
+msgstr "Zidong Baocun:"
+
+#: gui/options.cpp:1204
+msgid "Keys"
+msgstr "Guanjianzi"
+
+#: gui/options.cpp:1211
+msgid "GUI Language:"
+msgstr "Jiemian Yuyan:"
+
+#: gui/options.cpp:1211
+msgid "Language of ScummVM GUI"
+msgstr "ScummVM Jiemian Yuyan"
+
+#: gui/options.cpp:1239
+msgid "Update check:"
+msgstr ""
+
+#: gui/options.cpp:1239
+msgid "How often to check ScummVM updates"
+msgstr ""
+
+#: gui/options.cpp:1251
+msgid "Check now"
+msgstr ""
+
+#: gui/options.cpp:1386
+msgid "You have to restart ScummVM before your changes will take effect."
+msgstr "Nin Xuyao Chongqi ScummVM Lai Shi Genggai Shengxiao"
+
+#: gui/options.cpp:1419
+msgid "The chosen directory cannot be written to. Please select another one."
+msgstr "Zhiding de Mulu Buneng Xieru. Qing Xuanze Qita de Mulu."
+
+#: gui/options.cpp:1428
+msgid "Select directory for GUI themes"
+msgstr "Xuanze Jiemian Zhuti de Mulu"
+
+#: gui/options.cpp:1438
+msgid "Select directory for extra files"
+msgstr "Xuanze QIta Wenjian Mulu"
+
+#: gui/options.cpp:1449
+msgid "Select directory for plugins"
+msgstr "Xuanze Chajian Mulu"
+
+#: gui/options.cpp:1502
+msgid ""
+"The theme you selected does not support your current language. If you want "
+"to use this theme you need to switch to another language first."
+msgstr ""
+"Nin Xuanze de Zhuti Bu Zhichi Xianzai de Yuyan. Qing Xian Qiehuan Dao Qita "
+"Yuyan."
+
+#. I18N: You must leave "#" as is, only word 'next' is translatable
+#: gui/predictivedialog.cpp:86
+msgid "# next"
+msgstr "# Xia Yi Ge"
+
+#: gui/predictivedialog.cpp:87
+msgid "add"
+msgstr "Zengjia"
+
+#: gui/predictivedialog.cpp:92 gui/predictivedialog.cpp:167
+msgid "Delete char"
+msgstr "Shanchu Zifu"
+
+#: gui/predictivedialog.cpp:97 gui/predictivedialog.cpp:171
+msgid "<"
+msgstr "<"
+
+#. I18N: Pre means 'Predictive', leave '*' as is
+#: gui/predictivedialog.cpp:99 gui/predictivedialog.cpp:575
+msgid "* Pre"
+msgstr "* Guanci"
+
+#. I18N: 'Num' means Numbers
+#: gui/predictivedialog.cpp:578
+msgid "* Num"
+msgstr "* Shuzi"
+
+#. I18N: 'Abc' means Latin alphabet input
+#: gui/predictivedialog.cpp:581
+msgid "* Abc"
+msgstr "* Zimu"
+
+#: gui/recorderdialog.cpp:63
+msgid "Recorder or Playback Gameplay"
+msgstr "Youxi Luxiang Huo Huifang"
+
+#: gui/recorderdialog.cpp:68 gui/recorderdialog.cpp:155
+#: gui/saveload-dialog.cpp:220 gui/saveload-dialog.cpp:276
+msgid "Delete"
+msgstr "Shanchu"
+
+#: gui/recorderdialog.cpp:70
+msgid "Record"
+msgstr "Luxiang"
+
+#: gui/recorderdialog.cpp:71
+msgid "Playback"
+msgstr "Huifang"
+
+#: gui/recorderdialog.cpp:73
+msgid "Edit"
+msgstr "Binaji"
+
+#: gui/recorderdialog.cpp:85 gui/recorderdialog.cpp:242
+#: gui/recorderdialog.cpp:252
+msgid "Author: "
+msgstr "Zuozhe:"
+
+#: gui/recorderdialog.cpp:86 gui/recorderdialog.cpp:243
+#: gui/recorderdialog.cpp:253
+msgid "Notes: "
+msgstr "Zhushi:"
+
+#: gui/recorderdialog.cpp:154
+msgid "Do you really want to delete this record?"
+msgstr "Nin Zhende Xinagyao Shanchu Zhege Luxiang ma?"
+
+#: gui/recorderdialog.cpp:173
+msgid "Unknown Author"
+msgstr "Weizhi Zuozhe"
+
+#: gui/saveload-dialog.cpp:167
+msgid "List view"
+msgstr "Liebiao Shitu"
+
+#: gui/saveload-dialog.cpp:168
+msgid "Grid view"
+msgstr "Wangge Shitu"
+
+#: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:360
+msgid "No date saved"
+msgstr "Riqi Wei Baocun"
+
+#: gui/saveload-dialog.cpp:212 gui/saveload-dialog.cpp:361
+msgid "No time saved"
+msgstr "Shijian Wei Baocun"
+
+#: gui/saveload-dialog.cpp:213 gui/saveload-dialog.cpp:362
+msgid "No playtime saved"
+msgstr "Bofang Shijian Wei Baocun"
+
+#: gui/saveload-dialog.cpp:275
+msgid "Do you really want to delete this saved game?"
+msgstr "Nin Zhende Yao Shanchu Zhege Baocun Youxi ma?"
+
+#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:884
+msgid "Date: "
+msgstr "Riqi: "
+
+#: gui/saveload-dialog.cpp:389 gui/saveload-dialog.cpp:890
+msgid "Time: "
+msgstr "Shijian: "
+
+#: gui/saveload-dialog.cpp:395 gui/saveload-dialog.cpp:898
+msgid "Playtime: "
+msgstr "Bofang Shijian:"
+
+#: gui/saveload-dialog.cpp:408 gui/saveload-dialog.cpp:496
+msgid "Untitled savestate"
+msgstr "Wuming Baocun Zhuangtai"
+
+#: gui/saveload-dialog.cpp:548
+msgid "Next"
+msgstr "Xia Yi Ge"
+
+#: gui/saveload-dialog.cpp:551
+msgid "Prev"
+msgstr "Shang Yi Ge"
+
+#: gui/saveload-dialog.cpp:748
+msgid "New Save"
+msgstr "Xinjian Cundang"
+
+#: gui/saveload-dialog.cpp:748
+msgid "Create a new save game"
+msgstr "Chuangjian Yige Xin Cundang"
+
+#: gui/saveload-dialog.cpp:877
+msgid "Name: "
+msgstr "Mingcheng:"
+
+#: gui/saveload-dialog.cpp:951
+#, c-format
+msgid "Enter a description for slot %d:"
+msgstr "Shuru dui %d Dangwei de Miaoshu"
+
+#: gui/themebrowser.cpp:45
+msgid "Select a Theme"
+msgstr "Xuanze Zhuti"
+
+#: gui/ThemeEngine.cpp:415
+msgid "Disabled GFX"
+msgstr "Jinyong GFX"
+
+#: gui/ThemeEngine.cpp:415
+msgctxt "lowres"
+msgid "Disabled GFX"
+msgstr "Jinyong GFX"
+
+#: gui/ThemeEngine.cpp:416
+msgid "Standard Renderer"
+msgstr "Biaozhun Xuanranqi"
+
+#: gui/ThemeEngine.cpp:416 engines/scumm/dialogs.cpp:659
+msgid "Standard"
+msgstr "Biaozhun"
+
+#: gui/ThemeEngine.cpp:418
+msgid "Antialiased Renderer"
+msgstr "Fanjuchi Xuanranqi"
+
+#: gui/ThemeEngine.cpp:418
+msgid "Antialiased"
+msgstr "Fanjuchi"
+
+#: gui/updates-dialog.cpp:51
+msgid ""
+"ScummVM now supports automatic check for updates\n"
+"which requires access to the Internet.\n"
+"\n"
+"Would you like to enable this feature?"
+msgstr ""
+
+#: gui/updates-dialog.cpp:55
+msgid "(You can always enable it in the options dialog on the Misc tab)"
+msgstr ""
+
+#: gui/updates-dialog.cpp:92
+#, fuzzy
+msgid "Check for updates automatically"
+msgstr "Jiancha Gengxin..."
+
+#: gui/updates-dialog.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: gui/widget.cpp:366 gui/widget.cpp:368 gui/widget.cpp:374 gui/widget.cpp:376
+msgid "Clear value"
+msgstr "Qingchu Zhi"
+
+#: base/main.cpp:243
+#, c-format
+msgid "Engine does not support debug level '%s'"
+msgstr "Yinqing Buzhichi Tiaoshi Jibie ‘%s’"
+
+#: base/main.cpp:315
+msgid "Menu"
+msgstr "Caidan"
+
+#: base/main.cpp:318 backends/platform/symbian/src/SymbianActions.cpp:45
+#: backends/platform/wince/CEActionsPocket.cpp:45
+#: backends/platform/wince/CEActionsSmartphone.cpp:46
+msgid "Skip"
+msgstr "Tiaoguo"
+
+#: base/main.cpp:321 backends/platform/symbian/src/SymbianActions.cpp:50
+#: backends/platform/wince/CEActionsPocket.cpp:42
+msgid "Pause"
+msgstr "Zanting"
+
+#: base/main.cpp:324
+msgid "Skip line"
+msgstr "Tiaoguo Cihang"
+
+#: base/main.cpp:524
+msgid "Error running game:"
+msgstr "Youxi Yunxing Cuowu:"
+
+#: base/main.cpp:571
+msgid "Could not find any engine capable of running the selected game"
+msgstr "Wufa Zhaodao Shihe Yunxing Youxi de Yinqing"
+
+#: common/error.cpp:38
+msgid "No error"
+msgstr "Wu Cuowu"
+
+#: common/error.cpp:40
+msgid "Game data not found"
+msgstr "Youxi Shuju Weizhaodao"
+
+#: common/error.cpp:42
+msgid "Game id not supported"
+msgstr "Youxi id Bu Zhichi"
+
+#: common/error.cpp:44
+msgid "Unsupported color mode"
+msgstr "Buzhichi Secai Moshi"
+
+#: common/error.cpp:47
+msgid "Read permission denied"
+msgstr "Wu Duqu Quanxian"
+
+#: common/error.cpp:49
+msgid "Write permission denied"
+msgstr "Wu XIeru Quanxian"
+
+#: common/error.cpp:52
+msgid "Path does not exist"
+msgstr "Lujing Bu Cunzai"
+
+#: common/error.cpp:54
+msgid "Path not a directory"
+msgstr "Lujing Bushi Mulu"
+
+#: common/error.cpp:56
+msgid "Path not a file"
+msgstr "Lujing Bushi Wenjian"
+
+#: common/error.cpp:59
+msgid "Cannot create file"
+msgstr "Wufa Chuangjian Wenjian"
+
+#: common/error.cpp:61
+msgid "Reading data failed"
+msgstr "Duqu Shuju Shibai"
+
+#: common/error.cpp:63
+msgid "Writing data failed"
+msgstr "Xieru Shuju Shibai"
+
+#: common/error.cpp:66
+msgid "Could not find suitable engine plugin"
+msgstr "Wufa Zhaodao Heshi de Yinqing Chajian"
+
+#: common/error.cpp:68
+msgid "Engine plugin does not support save states"
+msgstr "Yingqing Chajian Buzhichi Baocun Zhuangtai"
+
+#: common/error.cpp:71
+msgid "User canceled"
+msgstr "Yonghu Quxiao"
+
+#: common/error.cpp:75
+msgid "Unknown error"
+msgstr "Weizhi Cuowu"
+
+#. I18N: Hercules is graphics card name
+#: common/rendermode.cpp:35
+msgid "Hercules Green"
+msgstr "Hercules Green"
+
+#: common/rendermode.cpp:36
+msgid "Hercules Amber"
+msgstr "Hercules Amber"
+
+#: common/rendermode.cpp:42
+msgid "PC-9821 (256 Colors)"
+msgstr "PC-9821 (256 Se)"
+
+#: common/rendermode.cpp:43
+msgid "PC-9801 (16 Colors)"
+msgstr "PC-9801 (16 Se)"
+
+#: common/rendermode.cpp:73
+msgctxt "lowres"
+msgid "Hercules Green"
+msgstr "Hercules Green"
+
+#: common/rendermode.cpp:74
+msgctxt "lowres"
+msgid "Hercules Amber"
+msgstr "Hercules Amber"
+
+#: common/updates.cpp:58
+msgid "Daily"
+msgstr ""
+
+#: common/updates.cpp:60
+msgid "Weekly"
+msgstr ""
+
+#: common/updates.cpp:62
+msgid "Monthly"
+msgstr ""
+
+#: common/updates.cpp:64
+#, fuzzy
+msgid "<Bad value>"
+msgstr "Qingchu Zhi"
+
+#: engines/advancedDetector.cpp:334
+#, c-format
+msgid "The game in '%s' seems to be unknown."
+msgstr "'%s' Zhong de Youxi Weizhi."
+
+#: engines/advancedDetector.cpp:335
+msgid "Please, report the following data to the ScummVM team along with name"
+msgstr "Qing JIang Xialie Shuju Yiji Youxi Baogao Gei ScummVM Tuandui"
+
+#: engines/advancedDetector.cpp:337
+msgid "of the game you tried to add and its version/language/etc.:"
+msgstr "BingQie Fushang Shitu Tianjia de Youximing Yiji Banben/Yuyan Deng"
+
+#: engines/dialogs.cpp:85
+msgid "~R~esume"
+msgstr "~R~Jixu"
+
+#: engines/dialogs.cpp:87 engines/mohawk/dialogs.cpp:96
+msgid "~L~oad"
+msgstr "~L~Zairu"
+
+#: engines/dialogs.cpp:91 engines/mohawk/dialogs.cpp:97
+msgid "~S~ave"
+msgstr "~S~Baocun"
+
+#: engines/dialogs.cpp:95
+msgid "~O~ptions"
+msgstr "~O~Xuanxiang"
+
+#: engines/dialogs.cpp:100
+msgid "~H~elp"
+msgstr "~H~Bangzhu"
+
+#: engines/dialogs.cpp:102
+msgid "~A~bout"
+msgstr "~A~Guanyu"
+
+#: engines/dialogs.cpp:105 engines/dialogs.cpp:181
+msgid "~R~eturn to Launcher"
+msgstr "~R~Fanhui Qidongqi"
+
+#: engines/dialogs.cpp:107 engines/dialogs.cpp:183
+msgctxt "lowres"
+msgid "~R~eturn to Launcher"
+msgstr "~R~Fanhui Qidongqi"
+
+#: engines/dialogs.cpp:116 engines/agi/saveload.cpp:761
+#: engines/avalanche/parser.cpp:1900 engines/cge/events.cpp:72
+#: engines/cge2/events.cpp:65 engines/cruise/menu.cpp:212
+#: engines/drascula/saveload.cpp:364 engines/dreamweb/saveload.cpp:262
+#: engines/hugo/file.cpp:298 engines/mohawk/dialogs.cpp:104
+#: engines/neverhood/menumodule.cpp:880 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
+msgid "Save game:"
+msgstr "Baocun Youxi:"
+
+#: engines/dialogs.cpp:116 backends/platform/symbian/src/SymbianActions.cpp:44
+#: backends/platform/wince/CEActionsPocket.cpp:43
+#: backends/platform/wince/CEActionsPocket.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:45
+#: backends/platform/wince/CEActionsSmartphone.cpp:231
+#: engines/agi/saveload.cpp:761 engines/avalanche/parser.cpp:1900
+#: engines/cge/events.cpp:72 engines/cge2/events.cpp:65
+#: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:364
+#: engines/dreamweb/saveload.cpp:262 engines/hugo/file.cpp:298
+#: engines/mohawk/dialogs.cpp:104 engines/neverhood/menumodule.cpp:880
+#: engines/parallaction/saveload.cpp:209 engines/pegasus/pegasus.cpp:377
+#: engines/sci/engine/kfile.cpp:713 engines/scumm/dialogs.cpp:184
+#: engines/sherlock/scalpel/scalpel.cpp:1250
+#: engines/sherlock/tattoo/widget_files.cpp:75 engines/toltecs/menu.cpp:291
+#: engines/toon/toon.cpp:3340 engines/tsage/scenes.cpp:599
+msgid "Save"
+msgstr "Baocun"
+
+#: engines/dialogs.cpp:145
+msgid ""
+"Sorry, this engine does not currently provide in-game help. Please consult "
+"the README for basic information, and for instructions on how to obtain "
+"further assistance."
+msgstr ""
+"Duibuqi, Ci Yinqing Buzhichi Youxi Nei Bangzhu. Qing Chayue README Lai Huoqu "
+"Jiben Xinxi Yiji Ruhe Huode Gengduo Bangzhu."
+
+#: engines/dialogs.cpp:234 engines/pegasus/pegasus.cpp:393
+#, c-format
+msgid ""
+"Gamestate save failed (%s)! Please consult the README for basic information, "
+"and for instructions on how to obtain further assistance."
+msgstr ""
+"Cundang Baocun Shibai (%s)! Qing Chayue README Huode Jiben Xinxi, Yiji "
+"Gengduo Xinxi"
+
+#: engines/dialogs.cpp:307 engines/mohawk/dialogs.cpp:100
+#: engines/tsage/dialogs.cpp:112
+msgid "~O~K"
+msgstr "~O~Queding"
+
+#: engines/dialogs.cpp:308 engines/mohawk/dialogs.cpp:101
+#: engines/tsage/dialogs.cpp:113
+msgid "~C~ancel"
+msgstr "~C~Quxiao"
+
+#: engines/dialogs.cpp:311
+msgid "~K~eys"
+msgstr "~K~Guanjianzi"
+
+#: engines/engine.cpp:342
+msgid "Could not initialize color format."
+msgstr "Wufa Chushihua Secai Geshi."
+
+#: engines/engine.cpp:350
+msgid "Could not switch to video mode: '"
+msgstr "Wufa Qiehuandao Shipin Moshi: '"
+
+#: engines/engine.cpp:359
+msgid "Could not apply aspect ratio setting."
+msgstr "Wufa Shezhi Bili Xuanxiang"
+
+#: engines/engine.cpp:364
+msgid "Could not apply fullscreen setting."
+msgstr "Wufa Shezhi Quanping Xuanxiang"
+
+#: engines/engine.cpp:464
+msgid ""
+"You appear to be playing this game directly\n"
+"from the CD. This is known to cause problems,\n"
+"and it is therefore recommended that you copy\n"
+"the data files to your hard disk instead.\n"
+"See the README file for details."
+msgstr ""
+"Sihu Ni Zhengzai Cong CD Zhong Yunxing\n"
+"Youxi. Zhe Keneng Hui Yinfa Wenti.\n"
+"Women Tuijian Nin Ba Shuju Wenjian\n"
+"Kaobei Dao Yingpan Zhong Lai Yunxing.\n"
+"Chakan README Huode Gengduo Xinxi."
+
+#: engines/engine.cpp:475
+msgid ""
+"This game has audio tracks in its disk. These\n"
+"tracks need to be ripped from the disk using\n"
+"an appropriate CD audio extracting tool in\n"
+"order to listen to the game's music.\n"
+"See the README file for details."
+msgstr ""
+"Ci Youxi Zai Guangpan Zhong Baohan Yinyue Wenjian. \n"
+"Zhexie Yingui Xuyao Yong Xiangying de CD Yinpin\n"
+"Jieya Gongju Kaobei Dao Cipan Zhong Cai Neng \n"
+"Bofang.\n"
+"Juti Xinxi Qing Chakan README."
+
+#: engines/engine.cpp:533
+#, c-format
+msgid ""
+"Gamestate load failed (%s)! Please consult the README for basic information, "
+"and for instructions on how to obtain further assistance."
+msgstr ""
+"Cundang Zairu Shibai (%s)! Qing Chayue README Huode Bangzhu XInxi Yiji "
+"Gengduo Bangzhu."
+
+#: engines/engine.cpp:546
+msgid ""
+"WARNING: The game you are about to start is not yet fully supported by "
+"ScummVM. As such, it is likely to be unstable, and any saves you make might "
+"not work in future versions of ScummVM."
+msgstr ""
+"Jinggao: Nin Yao Yunxing de Youxi Bingwei Wanquan Bei ScummVM Zhichi. Youxi "
+"Yunxing Youkeneng Buwending, Renhe Cundang Youkeneng zai Yihou de ScummVM "
+"Banben Bu Keyong."
+
+#: engines/engine.cpp:549
+msgid "Start anyway"
+msgstr "Qiangzhi Qidong"
+
+#: audio/adlib.cpp:2290
+msgid "AdLib Emulator"
+msgstr "AdLib Moniqi"
+
+#: audio/fmopl.cpp:62
+msgid "MAME OPL emulator"
+msgstr "MAME OPL Moniqi"
+
+#: audio/fmopl.cpp:64
+msgid "DOSBox OPL emulator"
+msgstr "DosBox OPL Moniqi"
+
+#: audio/fmopl.cpp:67
+msgid "ALSA Direct FM"
+msgstr "ALSA Direct FM"
+
+#: audio/mididrv.cpp:209
+#, c-format
+msgid ""
+"The selected audio device '%s' was not found (e.g. might be turned off or "
+"disconnected)."
+msgstr ""
+"Weizhaodao Xuanding de Yinpin Shebei '%s' (Liru, Youkeneng Guandiao Huozhe "
+"Weilianjie)."
+
+#: audio/mididrv.cpp:209 audio/mididrv.cpp:221 audio/mididrv.cpp:257
+#: audio/mididrv.cpp:272
+msgid "Attempting to fall back to the next available device..."
+msgstr "ZhengChangshi Xiayige Keyong Shebei..."
+
+#: audio/mididrv.cpp:221
+#, c-format
+msgid ""
+"The selected audio device '%s' cannot be used. See log file for more "
+"information."
+msgstr ""
+"Xuanding de Yinpin Shebei '%s' Wufa Shiyong. Chakan Rizhi Wenjian Huoqu "
+"Gengduo Xinxi."
+
+#: audio/mididrv.cpp:257
+#, c-format
+msgid ""
+"The preferred audio device '%s' was not found (e.g. might be turned off or "
+"disconnected)."
+msgstr ""
+"Youxian Yinpin Shebei '%s' WeiZhaodao (Liru, Youkeneng Guanbi Huo "
+"Weilianjie)."
+
+#: audio/mididrv.cpp:272
+#, c-format
+msgid ""
+"The preferred audio device '%s' cannot be used. See log file for more "
+"information."
+msgstr ""
+"Youxian Yinpin Shebei '%s' Wufa Shiyong. Chakan Rizhi Wenjian Huode Gengduo "
+"Xinxi."
+
+#: audio/mods/paula.cpp:196
+msgid "Amiga Audio Emulator"
+msgstr "Amiga Yinpin Moniqi"
+
+#: audio/null.h:44
+msgid "No music"
+msgstr "Wu Yinyue"
+
+#: audio/softsynth/appleiigs.cpp:33
+msgid "Apple II GS Emulator (NOT IMPLEMENTED)"
+msgstr "Apple II GS Moniqi (Wei Shixian)"
+
+#: audio/softsynth/cms.cpp:350
+msgid "Creative Music System Emulator"
+msgstr "Creative Music System Moniqi"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:33
+msgid "FM-Towns Audio"
+msgstr "FM-Towns Yinpin"
+
+#: audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp:58
+msgid "PC-98 Audio"
+msgstr "PC-98 Yinpin"
+
+#: audio/softsynth/mt32.cpp:196
+msgid "Initializing MT-32 Emulator"
+msgstr "Chushihua MT-32 Moniqi"
+
+#: audio/softsynth/mt32.cpp:434
+msgid "MT-32 Emulator"
+msgstr "MT-32 Moniqi"
+
+#: audio/softsynth/pcspk.cpp:139
+msgid "PC Speaker Emulator"
+msgstr "PC Yangshengqi Moniqi"
+
+#: audio/softsynth/pcspk.cpp:158
+msgid "IBM PCjr Emulator"
+msgstr "IBM PCjr Moniqi"
+
+#: audio/softsynth/sid.cpp:1430
+msgid "C64 Audio Emulator"
+msgstr "C64 Yinpin Moniqi"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Do you really want to return to the Launcher?"
+msgstr "Nin Zhende Xinagyao Fanhui Qidongqi Ma?"
+
+#: backends/events/default/default-events.cpp:196
+msgid "Launcher"
+msgstr "Qidongqi"
+
+#: backends/events/default/default-events.cpp:218
+msgid "Do you really want to quit?"
+msgstr "Nin Zhende Yao Tuichu Ma?"
+
+#: backends/events/default/default-events.cpp:218
+#: backends/platform/symbian/src/SymbianActions.cpp:52
+#: backends/platform/wince/CEActionsPocket.cpp:44
+#: backends/platform/wince/CEActionsSmartphone.cpp:52
+#: engines/scumm/dialogs.cpp:188 engines/scumm/help.cpp:83
+#: engines/scumm/help.cpp:85
+msgid "Quit"
+msgstr "Tuichu"
+
+#: backends/events/gph/gph-events.cpp:385
+#: backends/events/gph/gph-events.cpp:428
+#: backends/events/openpandora/op-events.cpp:168
+msgid "Touchscreen 'Tap Mode' - Left Click"
+msgstr "Chuping 'Chumo Moshi' - Zuojian Danji"
+
+#: backends/events/gph/gph-events.cpp:387
+#: backends/events/gph/gph-events.cpp:430
+#: backends/events/openpandora/op-events.cpp:170
+msgid "Touchscreen 'Tap Mode' - Right Click"
+msgstr "Chuping 'Chumo Moshi' - Youjian Danji"
+
+#: backends/events/gph/gph-events.cpp:389
+#: backends/events/gph/gph-events.cpp:432
+#: backends/events/openpandora/op-events.cpp:172
+msgid "Touchscreen 'Tap Mode' - Hover (No Click)"
+msgstr "Chuping 'Chumo Moshi' - Xuanting (Bu Danji)"
+
+#: backends/events/gph/gph-events.cpp:409
+msgid "Maximum Volume"
+msgstr "Zuida YInliang"
+
+#: backends/events/gph/gph-events.cpp:411
+msgid "Increasing Volume"
+msgstr "Zengda Yinliang"
+
+#: backends/events/gph/gph-events.cpp:417
+msgid "Minimal Volume"
+msgstr "Zuixiao Yinliang"
+
+#: backends/events/gph/gph-events.cpp:419
+msgid "Decreasing Volume"
+msgstr "Jianshao Yinliang"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Enabled"
+msgstr "Qidong Dianji"
+
+#: backends/events/maemosdl/maemosdl-events.cpp:180
+msgid "Clicking Disabled"
+msgstr "Jinyong Dianji"
+
+#: backends/events/openpandora/op-events.cpp:174
+msgid "Touchscreen 'Tap Mode' - Hover (DPad Clicks)"
+msgstr "Chuping 'Chumo Moshi' - Xuanting (Shoubing Dianji)"
+
+#: backends/events/symbiansdl/symbiansdl-events.cpp:186
+msgid "Do you want to quit ?"
+msgstr "Nin Zhende Yao Tuichu Ma?"
+
+#. I18N: Trackpad mode toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:308
+msgid "Trackpad mode is now"
+msgstr "Muqian Wei Chumoban Moshi"
+
+#. I18N: Trackpad mode on or off.
+#. I18N: Auto-drag on or off.
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "ON"
+msgstr "Kai"
+
+#: backends/events/webossdl/webossdl-events.cpp:311
+#: backends/events/webossdl/webossdl-events.cpp:338
+msgid "OFF"
+msgstr "Guan"
+
+#: backends/events/webossdl/webossdl-events.cpp:315
+msgid "Swipe two fingers to the right to toggle."
+msgstr "XiangYou Shiyong Liang Gen Shouzhi Huadong Qiehuan"
+
+#. I18N: Auto-drag toggle status.
+#: backends/events/webossdl/webossdl-events.cpp:335
+msgid "Auto-drag mode is now"
+msgstr "Muqian Wei Zidong Tuozhuai Moshi"
+
+#: backends/events/webossdl/webossdl-events.cpp:342
+msgid "Swipe three fingers to the right to toggle."
+msgstr "Xiangyou Huadong San Gen Shouzhi Qiehuan"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:126
+msgid "OpenGL"
+msgstr "OpenGL"
+
+#: backends/graphics/opengl/opengl-graphics.cpp:127
+msgid "OpenGL (No filtering)"
+msgstr "OpenGL"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:47
+#: backends/graphics/wincesdl/wincesdl-graphics.cpp:88
+#: backends/graphics/wincesdl/wincesdl-graphics.cpp:95
+msgid "Normal (no scaling)"
+msgstr "Putong"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:66
+msgctxt "lowres"
+msgid "Normal (no scaling)"
+msgstr "Putong"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2213
+msgid "Enabled aspect ratio correction"
+msgstr "Qiyong Bili Jiaozheng"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2219
+msgid "Disabled aspect ratio correction"
+msgstr "Jinyong Bili Jiaozheng"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2274
+msgid "Active graphics filter:"
+msgstr "Huodong de Tuxing Guolvqi:"
+
+#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2316
+msgid "Windowed mode"
+msgstr "Chuangkou Moshi"
+
+#: backends/keymapper/remap-dialog.cpp:48
+msgid "Keymap:"
+msgstr "Jianpan Yingshe:"
+
+#: backends/keymapper/remap-dialog.cpp:67
+msgid " (Effective)"
+msgstr " (Shengxiao)"
+
+#: backends/keymapper/remap-dialog.cpp:107
+msgid " (Active)"
+msgstr " (Huodong)"
+
+#: backends/keymapper/remap-dialog.cpp:107
+msgid " (Blocked)"
+msgstr " (Zuzhi)"
+
+#: backends/keymapper/remap-dialog.cpp:120
+msgid " (Global)"
+msgstr " (Quanju)"
+
+#: backends/keymapper/remap-dialog.cpp:128
+msgid " (Game)"
+msgstr " (Youxi)"
+
+#: backends/midi/windows.cpp:165
+msgid "Windows MIDI"
+msgstr "Windows MIDI"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:56
+#: engines/scumm/dialogs.cpp:287
+msgid "~C~lose"
+msgstr "~C~Guanbi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:57
+msgid "ScummVM Main Menu"
+msgstr "ScummVM Zhucaidan"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:63
+msgid "~L~eft handed mode"
+msgstr "~L~Zuoshou Moshi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:64
+msgid "~I~ndy fight controls"
+msgstr "~I~Indy fight Kongzhi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:65
+msgid "Show mouse cursor"
+msgstr "Xianshi Shubiao Zhizhen"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:66
+msgid "Snap to edges"
+msgstr "TieFu Yu Bianjie"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:68
+msgid "Touch X Offset"
+msgstr "Chumo X Pianyi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:75
+msgid "Touch Y Offset"
+msgstr "Chumo Y Pianyi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:87
+msgid "Use laptop trackpad-style cursor control"
+msgstr "Shiyong Bijiben Diannao Chumoban Shi Zhizhen Kongzhi"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:88
+msgid "Tap for left click, double tap right click"
+msgstr "Chumo Yici Wei Zuojian, Chumo LIangci Wei Youjian"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:90
+msgid "Sensitivity"
+msgstr "Mingandu"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:99
+msgid "Initial top screen scale:"
+msgstr "Chushi Shangping Daxiao"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:105
+msgid "Main screen scaling:"
+msgstr "Zhu Pingmu Daxiao"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:107
+msgid "Hardware scale (fast, but low quality)"
+msgstr "yingjian Suofang (Kuaisu DiXiao)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:108
+msgid "Software scale (good quality, but slower)"
+msgstr "Ruanjian Suofang (Gaoxiao Mansu)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:109
+msgid "Unscaled (you must scroll left and right)"
+msgstr "Wei Suofang (Xuyao ZuoYou Yidong)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:111
+msgid "Brightness:"
+msgstr "Liangdu:"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:121
+msgid "High quality audio (slower) (reboot)"
+msgstr "Gaozhiliang Yinpin (Man) (Chongqi)"
+
+#: backends/platform/ds/arm9/source/dsoptions.cpp:122
+msgid "Disable power off"
+msgstr "Jinyong Guanji"
+
+#: backends/platform/ios7/ios7_osys_events.cpp:309
+#: backends/platform/ios7/ios7_osys_events.cpp:519
+#: backends/platform/iphone/osys_events.cpp:300
+msgid "Mouse-click-and-drag mode enabled."
+msgstr "QIdong Shubiao Dianji-tuozhuai Moshi"
+
+#: backends/platform/ios7/ios7_osys_events.cpp:311
+#: backends/platform/ios7/ios7_osys_events.cpp:521
+#: backends/platform/iphone/osys_events.cpp:302
+msgid "Mouse-click-and-drag mode disabled."
+msgstr "Jinyong Shubiao Dianji-Tuozhuai Moshi."
+
+#: backends/platform/ios7/ios7_osys_events.cpp:322
+#: backends/platform/ios7/ios7_osys_events.cpp:540
+#: backends/platform/iphone/osys_events.cpp:313
+msgid "Touchpad mode enabled."
+msgstr "Qiyong Chumoban Moshi"
+
+#: backends/platform/ios7/ios7_osys_events.cpp:324
+#: backends/platform/ios7/ios7_osys_events.cpp:542
+#: backends/platform/iphone/osys_events.cpp:315
+msgid "Touchpad mode disabled."
+msgstr "Jinyong Chumoban Moshi"
+
+#: backends/platform/maemo/maemo.cpp:208
+msgid "Click Mode"
+msgstr "Danji Moshi"
+
+#: backends/platform/maemo/maemo.cpp:214
+#: backends/platform/symbian/src/SymbianActions.cpp:42
+#: backends/platform/tizen/form.cpp:275
+#: backends/platform/wince/CEActionsPocket.cpp:60
+#: backends/platform/wince/CEActionsSmartphone.cpp:43
+msgid "Left Click"
+msgstr "Zuojian Danji"
+
+#: backends/platform/maemo/maemo.cpp:217
+msgid "Middle Click"
+msgstr "Zhongjian Danji"
+
+#: backends/platform/maemo/maemo.cpp:220
+#: backends/platform/symbian/src/SymbianActions.cpp:43
+#: backends/platform/tizen/form.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:44
+msgid "Right Click"
+msgstr "Youjian Danji"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:88
+msgid "Hide ScummVM"
+msgstr "Yincang ScummVM"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:93
+msgid "Hide Others"
+msgstr "Yincang QIta"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:98
+msgid "Show All"
+msgstr "Xianshi Quanbu"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:120
+#: backends/platform/sdl/macosx/appmenu_osx.mm:131
+msgid "Window"
+msgstr "Chuangkou"
+
+#: backends/platform/sdl/macosx/appmenu_osx.mm:125
+msgid "Minimize"
+msgstr "Zuixiaohua"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:38
+#: backends/platform/wince/CEActionsSmartphone.cpp:39
+msgid "Up"
+msgstr "Shang"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:39
+#: backends/platform/wince/CEActionsSmartphone.cpp:40
+msgid "Down"
+msgstr "Xia"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:40
+#: backends/platform/wince/CEActionsSmartphone.cpp:41
+msgid "Left"
+msgstr "Zuo"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:41
+#: backends/platform/wince/CEActionsSmartphone.cpp:42
+msgid "Right"
+msgstr "You"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:46
+#: backends/platform/wince/CEActionsSmartphone.cpp:47
+msgid "Zone"
+msgstr "Quyu"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:47
+#: backends/platform/wince/CEActionsPocket.cpp:54
+#: backends/platform/wince/CEActionsSmartphone.cpp:48
+msgid "Multi Function"
+msgstr "Duo Gongneng"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:48
+msgid "Swap character"
+msgstr "Qiehuan Juese"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:49
+msgid "Skip text"
+msgstr "Tiaoguo Wenben"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:51
+msgid "Fast mode"
+msgstr "Kuaisu Moshi"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:53
+msgid "Debugger"
+msgstr "Tiaoshi Qi"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:54
+msgid "Global menu"
+msgstr "Quanju Caidan"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:55
+msgid "Virtual keyboard"
+msgstr "Xuni JIanpan"
+
+#: backends/platform/symbian/src/SymbianActions.cpp:56
+msgid "Key mapper"
+msgstr "Jianpan yingshe"
+
+#: backends/platform/tizen/form.cpp:263
+msgid "Right Click Once"
+msgstr "Youjian Danji"
+
+#: backends/platform/tizen/form.cpp:271
+msgid "Move Only"
+msgstr "Jin Yidong"
+
+#: backends/platform/tizen/form.cpp:294
+msgid "Escape Key"
+msgstr "Esc Jian"
+
+#: backends/platform/tizen/form.cpp:299
+msgid "Game Menu"
+msgstr "Youxi Caidan"
+
+#: backends/platform/tizen/form.cpp:304
+msgid "Show Keypad"
+msgstr "Xianshi Jianpan"
+
+#: backends/platform/tizen/form.cpp:309
+msgid "Control Mouse"
+msgstr "Kongzhi Shubiao"
+
+#: backends/platform/tizen/fs.cpp:259
+msgid "[ Data ]"
+msgstr "[ Shuju ]"
+
+#: backends/platform/tizen/fs.cpp:263
+msgid "[ Resources ]"
+msgstr "[ Ziyuan]"
+
+#: backends/platform/tizen/fs.cpp:267
+msgid "[ SDCard ]"
+msgstr "[ SD Ka ]"
+
+#: backends/platform/tizen/fs.cpp:271
+msgid "[ Media ]"
+msgstr "[ Meiti ]"
+
+#: backends/platform/tizen/fs.cpp:275
+msgid "[ Shared ]"
+msgstr "[ gongxiang ]"
+
+#: backends/platform/wii/options.cpp:51
+msgid "Video"
+msgstr "Shipin"
+
+#: backends/platform/wii/options.cpp:54
+msgid "Current video mode:"
+msgstr "Muqian Shipin Moshi:"
+
+#: backends/platform/wii/options.cpp:56
+msgid "Double-strike"
+msgstr "Shuang Ji"
+
+#: backends/platform/wii/options.cpp:60
+msgid "Horizontal underscan:"
+msgstr "Shuiping Saomiao"
+
+#: backends/platform/wii/options.cpp:66
+msgid "Vertical underscan:"
+msgstr "Chuizhi Saomiao"
+
+#: backends/platform/wii/options.cpp:71
+msgid "Input"
+msgstr "Shuru"
+
+#: backends/platform/wii/options.cpp:74
+msgid "GC Pad sensitivity:"
+msgstr "GC Pan Mingandu"
+
+#: backends/platform/wii/options.cpp:80
+msgid "GC Pad acceleration:"
+msgstr "GC Pad Jiasu"
+
+#: backends/platform/wii/options.cpp:86
+msgid "DVD"
+msgstr "DVD"
+
+#: backends/platform/wii/options.cpp:89 backends/platform/wii/options.cpp:101
+msgid "Status:"
+msgstr "Zhuangtai:"
+
+#: backends/platform/wii/options.cpp:90 backends/platform/wii/options.cpp:102
+msgid "Unknown"
+msgstr "Weizhi"
+
+#: backends/platform/wii/options.cpp:93
+msgid "Mount DVD"
+msgstr "Jiazai DVD"
+
+#: backends/platform/wii/options.cpp:94
+msgid "Unmount DVD"
+msgstr "Xiezai DVD"
+
+#: backends/platform/wii/options.cpp:98
+msgid "SMB"
+msgstr "SMB"
+
+#: backends/platform/wii/options.cpp:106
+msgid "Server:"
+msgstr "Fuwuqi:"
+
+#: backends/platform/wii/options.cpp:110
+msgid "Share:"
+msgstr "Gongxiang:"
+
+#: backends/platform/wii/options.cpp:114
+msgid "Username:"
+msgstr "Yonghuming:"
+
+#: backends/platform/wii/options.cpp:118
+msgid "Password:"
+msgstr "Mima:"
+
+#: backends/platform/wii/options.cpp:121
+msgid "Init network"
+msgstr "Chushihua Wangluo"
+
+#: backends/platform/wii/options.cpp:123
+msgid "Mount SMB"
+msgstr "Jiazai SMB"
+
+#: backends/platform/wii/options.cpp:124
+msgid "Unmount SMB"
+msgstr "Xiezai SMB"
+
+#: backends/platform/wii/options.cpp:143
+msgid "DVD Mounted successfully"
+msgstr "DVD Jiazai Chenggong"
+
+#: backends/platform/wii/options.cpp:146
+msgid "Error while mounting the DVD"
+msgstr "Jiazai DVD Chucuo"
+
+#: backends/platform/wii/options.cpp:148
+msgid "DVD not mounted"
+msgstr "DVD Wei Jiazai"
+
+#: backends/platform/wii/options.cpp:161
+msgid "Network up, share mounted"
+msgstr "Wangluo Lianjie, Gongxiang Jiazai"
+
+#: backends/platform/wii/options.cpp:163
+msgid "Network up"
+msgstr "Wangluo Lianjie"
+
+#: backends/platform/wii/options.cpp:166
+msgid ", error while mounting the share"
+msgstr ", Jiazai Gongxiang Chucuo"
+
+#: backends/platform/wii/options.cpp:168
+msgid ", share not mounted"
+msgstr ", Wei jiazai Gongxiang"
+
+#: backends/platform/wii/options.cpp:174
+msgid "Network down"
+msgstr "Wangluo Duanxian"
+
+#: backends/platform/wii/options.cpp:178
+msgid "Initializing network"
+msgstr "Chushihua Wnagluo"
+
+#: backends/platform/wii/options.cpp:182
+msgid "Timeout while initializing network"
+msgstr "Chushihua Wnagluo Chaoshi"
+
+#: backends/platform/wii/options.cpp:186
+#, c-format
+msgid "Network not initialized (%d)"
+msgstr "Wangluo Wei Chushihua (%d)"
+
+#: backends/platform/wince/CEActionsPocket.cpp:46
+msgid "Hide Toolbar"
+msgstr "YIncang Gongjulan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:47
+msgid "Show Keyboard"
+msgstr "Xianshi JIanpan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:48
+msgid "Sound on/off"
+msgstr "Shengyin Kai/Guan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:49
+msgid "Right click"
+msgstr "Youjian Danji"
+
+#: backends/platform/wince/CEActionsPocket.cpp:50
+msgid "Show/Hide Cursor"
+msgstr "Xianshi/Yincang Zhizhen"
+
+#: backends/platform/wince/CEActionsPocket.cpp:51
+msgid "Free look"
+msgstr "Ziyou Chakan"
+
+#: backends/platform/wince/CEActionsPocket.cpp:52
+msgid "Zoom up"
+msgstr "Fangda"
+
+#: backends/platform/wince/CEActionsPocket.cpp:53
+msgid "Zoom down"
+msgstr "Suoxiao"
+
+#: backends/platform/wince/CEActionsPocket.cpp:55
+#: backends/platform/wince/CEActionsSmartphone.cpp:49
+msgid "Bind Keys"
+msgstr "Bangding Jianwei"
+
+#: backends/platform/wince/CEActionsPocket.cpp:56
+msgid "Cursor Up"
+msgstr "Zhizhen Shang"
+
+#: backends/platform/wince/CEActionsPocket.cpp:57
+msgid "Cursor Down"
+msgstr "Zhizhen Xia"
+
+#: backends/platform/wince/CEActionsPocket.cpp:58
+msgid "Cursor Left"
+msgstr "Zhizhen Zuo"
+
+#: backends/platform/wince/CEActionsPocket.cpp:59
+msgid "Cursor Right"
+msgstr "Zhizhen You"
+
+#: backends/platform/wince/CEActionsPocket.cpp:267
+#: backends/platform/wince/CEActionsSmartphone.cpp:231
+msgid "Do you want to load or save the game?"
+msgstr "Nin Xinagyao Zairu Huo Baocun Youxi Ma?"
+
+#: backends/platform/wince/CEActionsPocket.cpp:326
+#: backends/platform/wince/CEActionsSmartphone.cpp:287
+msgid " Are you sure you want to quit ? "
+msgstr "Nin Queding Tuichu ma ?"
+
+#: backends/platform/wince/CEActionsSmartphone.cpp:50
+msgid "Keyboard"
+msgstr "Jianpan"
+
+#: backends/platform/wince/CEActionsSmartphone.cpp:51
+msgid "Rotate"
+msgstr "Xuanzhuan"
+
+#: backends/platform/wince/CELauncherDialog.cpp:56
+msgid "Using SDL driver "
+msgstr "Shiyong SDL Qudong"
+
+#: backends/platform/wince/CELauncherDialog.cpp:60
+msgid "Display "
+msgstr "Xianshi"
+
+#: backends/platform/wince/CELauncherDialog.cpp:83
+msgid "Do you want to perform an automatic scan ?"
+msgstr "Nin Xiwang Zidong Saomiao ma?"
+
+#: backends/platform/wince/wince-sdl.cpp:516
+msgid "Map right click action"
+msgstr "Yingshe Youjian Dianji Xingwei"
+
+#: backends/platform/wince/wince-sdl.cpp:520
+msgid "You must map a key to the 'Right Click' action to play this game"
+msgstr "Nin Bixu Yingshe Yige Jian Dao 'Youjian Danji' Lai kaishi Youxi"
+
+#: backends/platform/wince/wince-sdl.cpp:529
+msgid "Map hide toolbar action"
+msgstr "yingshe YIncang Gongjulan Xingwei"
+
+#: backends/platform/wince/wince-sdl.cpp:533
+msgid "You must map a key to the 'Hide toolbar' action to play this game"
+msgstr "Nin Bixu Yingshe Yigejian Dao 'Yincang Gongjulan' Lai Kaishi Youxi"
+
+#: backends/platform/wince/wince-sdl.cpp:542
+msgid "Map Zoom Up action (optional)"
+msgstr "Yingshe Fnagda Xingwei (Kexuan)"
+
+#: backends/platform/wince/wince-sdl.cpp:545
+msgid "Map Zoom Down action (optional)"
+msgstr "Yingshe Suoxiao Xingwei (Kexuan)"
+
+#: backends/platform/wince/wince-sdl.cpp:553
+msgid ""
+"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory"
+msgstr ""
+"Buyao Wnagji Yingshe YIge Jian Dao 'YIncang Gongjulan' Lai Chakan Suoyou "
+"xiang"
+
+#: backends/updates/macosx/macosx-updates.mm:79
+msgid "Check for Updates..."
+msgstr "Jiancha Gengxin..."
+
+#: engines/adl/detection.cpp:43 engines/adl/detection.cpp:53
+#, fuzzy
+msgid "Color mode"
+msgstr "Semang Moshi"
+
+#: engines/adl/detection.cpp:44 engines/adl/detection.cpp:54
+msgid "Use color graphics"
+msgstr ""
+
+#: engines/adl/detection.cpp:63
+msgid "Scanlines"
+msgstr ""
+
+#: engines/adl/detection.cpp:64
+#, fuzzy
+msgid "Show scanlines"
+msgstr "Xianshi Wuti Biaoqian"
+
+#: engines/agi/detection.cpp:147 engines/cine/detection.cpp:70
+#: engines/drascula/detection.cpp:302 engines/dreamweb/detection.cpp:48
+#: engines/neverhood/detection.cpp:177 engines/sci/detection.cpp:424
+#: engines/toltecs/detection.cpp:200 engines/zvision/detection_tables.h:51
+msgid "Use original save/load screens"
+msgstr "Shiyong Yuanshi Baocun/Zairu Pingmu"
+
+#: engines/agi/detection.cpp:148 engines/cine/detection.cpp:71
+#: engines/drascula/detection.cpp:303 engines/dreamweb/detection.cpp:49
+#: engines/neverhood/detection.cpp:178 engines/sci/detection.cpp:425
+#: engines/toltecs/detection.cpp:201
+msgid "Use the original save/load screens, instead of the ScummVM ones"
+msgstr "Shiyong Yuanshi Baocun/Zairu Pingmu, Bu Shiyong ScummVM de"
+
+#: engines/agi/detection.cpp:157
+msgid "Use an alternative palette"
+msgstr "Shiyong Qita Mianban"
+
+#: engines/agi/detection.cpp:158
+msgid ""
+"Use an alternative palette, common for all Amiga games. This was the old "
+"behavior"
+msgstr "Shiyong QIta Mianban, Yiban Yonghu suoyou de Amiga Youxi. "
+
+#: engines/agi/detection.cpp:167
+msgid "Mouse support"
+msgstr "Shubiao Zhichi"
+
+#: engines/agi/detection.cpp:168
+msgid ""
+"Enables mouse support. Allows to use mouse for movement and in game menus."
+msgstr ""
+"Qiyong shubiao zhichi. Yunxu Shiyong Shubiao jinxing Yidong He Youxi Nei "
+"Caidan"
+
+#: engines/agi/detection.cpp:177
+#, fuzzy
+msgid "Use Hercules hires font"
+msgstr "Hercules Green"
+
+#: engines/agi/detection.cpp:178
+msgid "Uses Hercules hires font, when font file is available."
+msgstr ""
+
+#: engines/agi/detection.cpp:187
+msgid "Pause when entering commands"
+msgstr ""
+
+#: engines/agi/detection.cpp:188
+msgid ""
+"Shows a command prompt window and pauses the game (like in SCI) instead of a "
+"real-time prompt."
+msgstr ""
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
+msgid "Restore game:"
+msgstr "Huifu Youxi:"
+
+#: engines/agi/saveload.cpp:774 engines/avalanche/parser.cpp:1888
+#: engines/cge/events.cpp:83 engines/cge2/events.cpp:76
+#: engines/drascula/saveload.cpp:377 engines/dreamweb/saveload.cpp:170
+#: engines/hugo/file.cpp:400 engines/neverhood/menumodule.cpp:893
+#: engines/sci/engine/kfile.cpp:834 engines/sherlock/scalpel/scalpel.cpp:1263
+#: engines/sherlock/tattoo/widget_files.cpp:94 engines/toltecs/menu.cpp:266
+#: engines/toon/toon.cpp:3432
+msgid "Restore"
+msgstr "Huifu"
+
+#: engines/agos/saveload.cpp:159 engines/scumm/scumm.cpp:2395
+#, c-format
+msgid ""
+"Failed to load game state from file:\n"
+"\n"
+"%s"
+msgstr ""
+"Jiazai Youxi Cundang Shibai:\n"
+"\n"
+"%s"
+
+#: engines/agos/saveload.cpp:194 engines/scumm/scumm.cpp:2388
+#, c-format
+msgid ""
+"Failed to save game state to file:\n"
+"\n"
+"%s"
+msgstr ""
+"Baocun Youxi Cundang Shibai:\n"
+"\n"
+"%s"
+
+#: engines/agos/saveload.cpp:202 engines/scumm/scumm.cpp:2406
+#, c-format
+msgid ""
+"Successfully saved game state in file:\n"
+"\n"
+"%s"
+msgstr ""
+"Chenggong Baocun Youxi Cundang:\n"
+"\n"
+"%s"
+
+#: engines/agos/animation.cpp:558
+#, c-format
+msgid "Cutscene file '%s' not found!"
+msgstr "Changjing Qiehuan Wenjian '%s' Wei Zhaodao!"
+
+#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:101
+msgid "Color Blind Mode"
+msgstr "Semang Moshi"
+
+#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:102
+msgid "Enable Color Blind Mode by default"
+msgstr "Moren Qiyong Semang Moshi"
+
+#: engines/drascula/saveload.cpp:47
+msgid ""
+"ScummVM found that you have old savefiles for Drascula that should be "
+"converted.\n"
+"The old save game format is no longer supported, so you will not be able to "
+"load your games if you don't convert them.\n"
+"\n"
+"Press OK to convert them now, otherwise you will be asked again the next "
+"time you start the game.\n"
+msgstr ""
+"ScummVM Faxian Nin You Jiu de Drascula de Cundang Wenjian Xuyao Bei "
+"Zhuanhuan.\n"
+"Jiude cundang Wenjian Buzai Zhichi, Suoyi Nin Buneng Guo zai Zhuanhuan "
+"Zhiqian Duqu.\n"
+"Dianji Shi Lai Xianzai Zhuanhuan, Fouze Xiaci Qidong Youxi Shi Nin Huibei "
+"Zaici Xunwen\n"
+" \n"
+
+#: engines/dreamweb/detection.cpp:58
+msgid "Use bright palette mode"
+msgstr "Shiyong Liang Tiaoseban Moshi"
+
+#: engines/dreamweb/detection.cpp:59
+msgid "Display graphics using the game's bright palette"
+msgstr "Shiyong youxi de Liang Tiaoseban Lai Xianshi Tuxiang"
+
+#: engines/gob/inter_playtoons.cpp:255 engines/gob/inter_v2.cpp:1467
+#: engines/gob/inter_geisha.cpp:232 engines/tinsel/saveload.cpp:532
+msgid "Failed to load game state from file."
+msgstr "Wufa Cong Cundang Wenjian Zhong Duqu"
+
+#: engines/gob/inter_v2.cpp:1537 engines/gob/inter_geisha.cpp:263
+#: engines/tinsel/saveload.cpp:545
+msgid "Failed to save game state to file."
+msgstr "Wufa Baocun Cundang "
+
+#: engines/gob/inter_v5.cpp:107
+msgid "Failed to delete file."
+msgstr "Wufa Shanchu Wenjian"
+
+#: engines/groovie/detection.cpp:312
+msgid "Fast movie speed"
+msgstr "Kuaisu Yingpian"
+
+#: engines/groovie/detection.cpp:313
+msgid "Play movies at an increased speed"
+msgstr "Yong Gengkuai de Sudu Bofang Yingpian"
+
+#: engines/groovie/script.cpp:407
+msgid "Failed to save game"
+msgstr "Wufa baocun Youxi"
+
+#: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86
+msgid "Gore Mode"
+msgstr "Gore Moshi"
+
+#: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87
+msgid "Enable Gore Mode when available"
+msgstr "Dang Kexing Shi Qiyong Gore Moshi"
+
+#. I18N: Studio audience adds an applause and cheering sounds whenever
+#. Malcolm makes a joke.
+#: engines/kyra/detection.cpp:62
+msgid "Studio audience"
+msgstr "Luyinpeng Guanzhong"
+
+#: engines/kyra/detection.cpp:63
+msgid "Enable studio audience"
+msgstr "Qiyong Luyinpeng Guanzhong"
+
+#. I18N: This option allows the user to skip text and cutscenes.
+#: engines/kyra/detection.cpp:73
+msgid "Skip support"
+msgstr "Zhichi Tiaoguo"
+
+#: engines/kyra/detection.cpp:74
+msgid "Allow text and cutscenes to be skipped"
+msgstr "Zhichi Wenzi he Changjing Bei Tiaoguo"
+
+#. I18N: Helium mode makes people sound like they've inhaled Helium.
+#: engines/kyra/detection.cpp:84
+msgid "Helium mode"
+msgstr "Haiqi Moshi"
+
+#: engines/kyra/detection.cpp:85
+msgid "Enable helium mode"
+msgstr "Shiyong Haiqi Moshi"
+
+#. I18N: When enabled, this option makes scrolling smoother when
+#. changing from one screen to another.
+#: engines/kyra/detection.cpp:99
+msgid "Smooth scrolling"
+msgstr "Pinghua Gundong"
+
+#: engines/kyra/detection.cpp:100
+msgid "Enable smooth scrolling when walking"
+msgstr "Qiyong Zoulu Shi de pinghua Gundong"
+
+#. I18N: When enabled, this option changes the cursor when it floats to the
+#. edge of the screen to a directional arrow. The player can then click to
+#. walk towards that direction.
+#: engines/kyra/detection.cpp:112
+msgid "Floating cursors"
+msgstr "Xuanfu Guangbiao"
+
+#: engines/kyra/detection.cpp:113
+msgid "Enable floating cursors"
+msgstr "Qiyong Xuanfu Guangbiao"
+
+#. I18N: HP stands for Hit Points
+#: engines/kyra/detection.cpp:127
+msgid "HP bar graphs"
+msgstr "HP Tiao Tu"
+
+#: engines/kyra/detection.cpp:128
+msgid "Enable hit point bar graphs"
+msgstr "Qiyong Jida Dian Tiao Tu"
+
+#: engines/kyra/lol.cpp:478
+msgid "Attack 1"
+msgstr "Gongji 1"
+
+#: engines/kyra/lol.cpp:479
+msgid "Attack 2"
+msgstr "Gongji 2"
+
+#: engines/kyra/lol.cpp:480
+msgid "Attack 3"
+msgstr "Gongji 3"
+
+#: engines/kyra/lol.cpp:481
+msgid "Move Forward"
+msgstr "Xiangqian Yidong"
+
+#: engines/kyra/lol.cpp:482
+msgid "Move Back"
+msgstr "Xinaghou Yidong"
+
+#: engines/kyra/lol.cpp:483
+msgid "Slide Left"
+msgstr "Xiangzuo Huadong"
+
+#: engines/kyra/lol.cpp:484
+msgid "Slide Right"
+msgstr "Xiangyou Huadong"
+
+#: engines/kyra/lol.cpp:485 engines/pegasus/pegasus.cpp:2509
+msgid "Turn Left"
+msgstr "Zuozhuan"
+
+#: engines/kyra/lol.cpp:486 engines/pegasus/pegasus.cpp:2510
+msgid "Turn Right"
+msgstr "Youzhuan"
+
+#: engines/kyra/lol.cpp:487
+msgid "Rest"
+msgstr "Xiuxi"
+
+#: engines/kyra/lol.cpp:488
+msgid "Options"
+msgstr "Xuanxiang"
+
+#: engines/kyra/lol.cpp:489
+msgid "Choose Spell"
+msgstr "Xuanze Pinxie"
+
+#: engines/kyra/sound_midi.cpp:477
+msgid ""
+"You appear to be using a General MIDI device,\n"
+"but your game only supports Roland MT32 MIDI.\n"
+"We try to map the Roland MT32 instruments to\n"
+"General MIDI ones. It is still possible that\n"
+"some tracks sound incorrect."
+msgstr ""
+"Nin Sihu zhengzai shiyong yige Tongyong MIDI Shebei\n"
+"Danshi Nin de Youxi jinzhichi Roland MT32 MIDI.\n"
+"Women zhengzai changshi JIang Roland MT32 Yingshe\n"
+"wei Tongyong MIDI. Youxie YIngui Rengran Youkeneng\n"
+"Bu zheng que."
+
+#: engines/kyra/saveload_eob.cpp:557
+#, c-format
+msgid ""
+"The following original save game file has been found in your game path:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Do you wish to use this save game file with ScummVM?\n"
+"\n"
+msgstr ""
+"Xialie Yuanshi Cundang Wenjian Zai Nin de Youxi Lujing Zhong:\n"
+"\n"
+"%s %s\n"
+"\n"
+"Nin Xiwang Shiyong Zhege ScummVM Cundang Wenjian ma?\n"
+"\n"
+
+#: engines/kyra/saveload_eob.cpp:590
+#, c-format
+msgid ""
+"A save game file was found in the specified slot %d. Overwrite?\n"
+"\n"
+msgstr ""
+"Zai Cundang %d Zhong Yifaxian Baocun de Youxi WEnjian. Fugai Ma?\n"
+"\n"
+
+#: engines/kyra/saveload_eob.cpp:623
+#, c-format
+msgid ""
+"%d original save game files have been successfully imported into\n"
+"ScummVM. If you want to manually import original save game files later you "
+"will\n"
+"need to open the ScummVM debug console and use the command "
+"'import_savefile'.\n"
+"\n"
+msgstr ""
+"%d Ge yuanshi Cundang Youxi Wenjian Chenggong Daoru Daole\n"
+"ScummVM. Ruguo Nin Xinag Zhihou Rengong Daoru Cundang Wenjian, Nin Xuyao\n"
+"Dagai ScummVM Tiaoshi Kongzhitai, Bingqie shiyong mingling "
+"'import_savefile'.\n"
+"\n"
+
+#: engines/mohawk/detection.cpp:169
+msgid "Play the Myst fly by movie"
+msgstr ""
+
+#: engines/mohawk/detection.cpp:170
+msgid "The Myst fly by movie was not played by the original engine."
+msgstr ""
+
+#. I18N: Option for fast scene switching
+#: engines/mohawk/dialogs.cpp:178 engines/mohawk/dialogs.cpp:264
+msgid "~Z~ip Mode Activated"
+msgstr "~Z~Yasuo Moshi Qidong"
+
+#: engines/mohawk/dialogs.cpp:179
+msgid "~T~ransitions Enabled"
+msgstr "~T~Qiyong Zhuanyi"
+
+#. I18N: Drop book page
+#: engines/mohawk/dialogs.cpp:181
+msgid "~D~rop Page"
+msgstr "~D~shanchu Yemian"
+
+#: engines/mohawk/dialogs.cpp:185
+#, fuzzy
+msgid "Show ~M~ap"
+msgstr "~S~Xianshi Ditu"
+
+#: engines/mohawk/dialogs.cpp:191
+#, fuzzy
+msgid "Main Men~u~"
+msgstr "~M~Zhucaidan"
+
+#: engines/mohawk/dialogs.cpp:265
+msgid "~W~ater Effect Enabled"
+msgstr "~W~Qiyong Shuimian Xiaoguo"
+
+#: engines/neverhood/detection.cpp:184
+msgid "Skip the Hall of Records storyboard scenes"
+msgstr "Tiaoguo Hall of Records Jishiban Changjing"
+
+#: engines/neverhood/detection.cpp:185
+msgid "Allows the player to skip past the Hall of Records storyboard scenes"
+msgstr "Yunxu Wanjia Tiaoguo Hall of Records Jishiban Changjing"
+
+#: engines/neverhood/detection.cpp:191
+msgid "Scale the making of videos to full screen"
+msgstr "Fangda Shipin Zhizuo Dao Quanping"
+
+#: engines/neverhood/detection.cpp:192
+msgid "Scale the making of videos, so that they use the whole screen"
+msgstr "Suofang Shipin Zhizuo, Quanping Ke Yong"
+
+#: engines/parallaction/saveload.cpp:130
+#, c-format
+msgid ""
+"Can't save game in slot %i\n"
+"\n"
+msgstr ""
+"Wufa Baocun Youxi Dao Kongwei %i\n"
+"\n"
+
+#: engines/parallaction/saveload.cpp:194
+msgid "Load file"
+msgstr "Zairu Wenjian"
+
+#: engines/parallaction/saveload.cpp:201
+msgid "Loading game..."
+msgstr "Zairu youxi..."
+
+#: engines/parallaction/saveload.cpp:209
+msgid "Save file"
+msgstr "Baocun Wenjian"
+
+#: engines/parallaction/saveload.cpp:216
+msgid "Saving game..."
+msgstr "Baocun Youxi..."
+
+#: engines/parallaction/saveload.cpp:269
+msgid ""
+"ScummVM found that you have old savefiles for Nippon Safes that should be "
+"renamed.\n"
+"The old names are no longer supported, so you will not be able to load your "
+"games if you don't convert them.\n"
+"\n"
+"Press OK to convert them now, otherwise you will be asked next time.\n"
+msgstr ""
+"ScummVM Faxian Youyixie Nippon Safes de Cundang Wenjian xuyao Gaiming.\n"
+"Yuanlai de wenjianming Buzai Bei Zhichi, Ruguo Bujing Zhuanhuan Ninjing "
+"Buneng Zairu Tamen.\n"
+"Dianji Queding Lai Xianzai Zhuanhuan, Fouze Nin Hui zai Xiaci Bei Xunwen\n"
+
+#: engines/parallaction/saveload.cpp:316
+msgid "ScummVM successfully converted all your savefiles."
+msgstr "ScummVM Chenggong Zhuanhuan le Nin de Suoyou Cundang Wenjian."
+
+#: engines/parallaction/saveload.cpp:318
+msgid ""
+"ScummVM printed some warnings in your console window and can't guarantee all "
+"your files have been converted.\n"
+"\n"
+"Please report to the team."
+msgstr ""
+"ScummVM zai Kongzhitai Zhong Youyixie Jinggai, Bingqie Women Buneng Baozheng "
+"Suoyou de wenjian doubei zhuanhuan\n"
+".\n"
+"\n"
+"QIng Jiang Qingkuang Baogao Gei Tuandui."
+
+#: engines/pegasus/pegasus.cpp:714
+msgid "Invalid save file name"
+msgstr "Wuxiao Baocun Wenjianming"
+
+#: engines/pegasus/pegasus.cpp:2507
+msgid "Up/Zoom In/Move Forward/Open Doors"
+msgstr "Xiangshang/fangda/Qianjin/Kaimen"
+
+#: engines/pegasus/pegasus.cpp:2508
+msgid "Down/Zoom Out"
+msgstr "Xiangxia/Suoxiao"
+
+#: engines/pegasus/pegasus.cpp:2511
+msgid "Display/Hide Inventory Tray"
+msgstr "Xianshi/Yincang Wupinlan"
+
+#: engines/pegasus/pegasus.cpp:2512
+msgid "Display/Hide Biochip Tray"
+msgstr "Xianshi/Yincang Biochip Lan"
+
+#: engines/pegasus/pegasus.cpp:2513
+msgid "Action/Select"
+msgstr "Dongzuo/Xuanze"
+
+#: engines/pegasus/pegasus.cpp:2514
+msgid "Toggle Center Data Display"
+msgstr "Qiehuan Shuju Zhongxin Xianshi"
+
+#: engines/pegasus/pegasus.cpp:2515
+msgid "Display/Hide Info Screen"
+msgstr "Xianshi/Yincang Xinxi Pingmu"
+
+#: engines/pegasus/pegasus.cpp:2516
+msgid "Display/Hide Pause Menu"
+msgstr "Xianshi/Yincang Zanting Caidan"
+
+#: engines/queen/detection.cpp:56
+msgid "Alternative intro"
+msgstr "QIta Jieshao"
+
+#: engines/queen/detection.cpp:57
+msgid "Use an alternative game intro (CD version only)"
+msgstr "Shiyong Qita Youxi Jieshao (Jin CD Ban)"
+
+#: engines/sci/detection.cpp:384
+msgid "Skip EGA dithering pass (full color backgrounds)"
+msgstr "Tiaoguo EGA Doudong (quancai Beijing)"
+
+#: engines/sci/detection.cpp:385
+msgid "Skip dithering pass in EGA games, graphics are shown with full colors"
+msgstr "tiaoguo EGA Youxi Zhong de Doudong, Tuxiang Yi Quancai Xianshi"
+
+#: engines/sci/detection.cpp:394
+msgid "Enable high resolution graphics"
+msgstr "QIyong Gaofenbianlv Tu"
+
+#: engines/sci/detection.cpp:395
+msgid "Enable high resolution graphics/content"
+msgstr "Qiyong Gaofenbianlv Tubian/Neirong"
+
+#: engines/sci/detection.cpp:404
+msgid "Enable black-lined video"
+msgstr ""
+
+#: engines/sci/detection.cpp:405
+msgid "Draw black lines over videos to increase their apparent sharpness"
+msgstr ""
+
+#: engines/sci/detection.cpp:414
+msgid "Prefer digital sound effects"
+msgstr "Youxianshiyong Shuzi Yinxiao"
+
+#: engines/sci/detection.cpp:415
+msgid "Prefer digital sound effects instead of synthesized ones"
+msgstr "Youxian SHiyong shuzi YInxiao, er fei Hecheng"
+
+#: engines/sci/detection.cpp:434
+msgid "Use IMF/Yamaha FB-01 for MIDI output"
+msgstr "Shiyong IMF/yamaha Fb-01 Huo MIDI shuchu"
+
+#: engines/sci/detection.cpp:435
+msgid ""
+"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI "
+"output"
+msgstr ""
+"Shiyong IBM Music Feature Ka Huozhe Yamaha FB-01 FM hecheng Mokuai zuowei "
+"MIDI shuchu"
+
+#: engines/sci/detection.cpp:445
+msgid "Use CD audio"
+msgstr "Shiyong CD YInpin"
+
+#: engines/sci/detection.cpp:446
+msgid "Use CD audio instead of in-game audio, if available"
+msgstr "Shiyong CD Yinpin erfei Youxinei Yinpin (ruguo keyong)"
+
+#: engines/sci/detection.cpp:456
+msgid "Use Windows cursors"
+msgstr "Shiyong WIndows Guangbiao"
+
+#: engines/sci/detection.cpp:457
+msgid ""
+"Use the Windows cursors (smaller and monochrome) instead of the DOS ones"
+msgstr "Shiyong Windows Guangbiao (gengxiao Danse) erfei DOS Guangbiao"
+
+#: engines/sci/detection.cpp:467
+msgid "Use silver cursors"
+msgstr "Shiyong Yinse Guangbiao"
+
+#: engines/sci/detection.cpp:468
+msgid ""
+"Use the alternate set of silver cursors, instead of the normal golden ones"
+msgstr "Shiyong Qita Yinse Guangbiao"
+
+#: engines/scumm/detection.cpp:1340
+#, fuzzy
+msgid "Show Object Line"
+msgstr "Xianshi Wuti Biaoqian"
+
+#: engines/scumm/detection.cpp:1341
+msgid "Show the names of objects at the bottom of the screen"
+msgstr ""
+
+#: engines/scumm/dialogs.cpp:172
+#, c-format
+msgid "Insert Disk %c and Press Button to Continue."
+msgstr "Charu Guangpan %c Bing An Anniu YI jixu"
+
+#: engines/scumm/dialogs.cpp:173
+#, c-format
+msgid "Unable to Find %s, (%c%d) Press Button."
+msgstr "Wufa zhaodao %s, (%c%d) Qing an anniu."
+
+#: engines/scumm/dialogs.cpp:174
+#, c-format
+msgid "Error reading disk %c, (%c%d) Press Button."
+msgstr "Duqu Guangpan %c Cuowu, (%c%d) Qing An Anniu."
+
+#: engines/scumm/dialogs.cpp:175
+msgid "Game Paused. Press SPACE to Continue."
+msgstr "Youxi Zanting. An Kongge Yi jixu."
+
+#. I18N: You may specify 'Yes' symbol at the end of the line, like this:
+#. "Moechten Sie wirklich neu starten? (J/N)J"
+#. Will react to J as 'Yes'
+#: engines/scumm/dialogs.cpp:179
+msgid "Are you sure you want to restart? (Y/N)Y"
+msgstr "NinQueding Yao Chongqi ma? (Y/N)Y"
+
+#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment
+#: engines/scumm/dialogs.cpp:181
+msgid "Are you sure you want to quit? (Y/N)Y"
+msgstr "NinQueding Yao Tuichu Ma? (Y/N)Y"
+
+#: engines/scumm/dialogs.cpp:186
+msgid "Play"
+msgstr "Kaishi"
+
+#: engines/scumm/dialogs.cpp:190
+msgid "Insert save/load game disk"
+msgstr "Charu Cundang/Duqu youxi Guangpan"
+
+#: engines/scumm/dialogs.cpp:191
+msgid "You must enter a name"
+msgstr "Nin bixu Shuru Yige Mingcheng"
+
+#: engines/scumm/dialogs.cpp:192
+msgid "The game was NOT saved (disk full?)"
+msgstr "Youxi Meiyou Baocun (Cipan Kongjian YIman?)"
+
+#: engines/scumm/dialogs.cpp:193
+msgid "The game was NOT loaded"
+msgstr "Youxi Meiyou Jiazai"
+
+#: engines/scumm/dialogs.cpp:194
+#, c-format
+msgid "Saving '%s'"
+msgstr "Baocun '%s'"
+
+#: engines/scumm/dialogs.cpp:195
+#, c-format
+msgid "Loading '%s'"
+msgstr "Zairu '%s'"
+
+#: engines/scumm/dialogs.cpp:196
+msgid "Name your SAVE game"
+msgstr "Wei baocun Youxi Qiming"
+
+#: engines/scumm/dialogs.cpp:197
+msgid "Select a game to LOAD"
+msgstr "Qing Xuanze Yige Youxi Jiazai"
+
+#: engines/scumm/dialogs.cpp:198
+msgid "Game title)"
+msgstr "Youxi Biaoti)"
+
+#. I18N: Previous page button
+#: engines/scumm/dialogs.cpp:284
+msgid "~P~revious"
+msgstr "~P~Shangyige"
+
+#. I18N: Next page button
+#: engines/scumm/dialogs.cpp:286
+msgid "~N~ext"
+msgstr "~N~Xiayige"
+
+#: engines/scumm/dialogs.cpp:598
+msgid "Speech Only"
+msgstr "Jin Yuyin"
+
+#: engines/scumm/dialogs.cpp:599
+msgid "Speech and Subtitles"
+msgstr "Yuyin he Zimu"
+
+#: engines/scumm/dialogs.cpp:600
+msgid "Subtitles Only"
+msgstr "Jin Zimu"
+
+#: engines/scumm/dialogs.cpp:608
+msgctxt "lowres"
+msgid "Speech & Subs"
+msgstr "Yuyin He Zimu"
+
+#: engines/scumm/dialogs.cpp:654
+msgid "Select a Proficiency Level."
+msgstr "Qing Xuanze Shulian Dengji"
+
+#: engines/scumm/dialogs.cpp:656
+msgid "Refer to your Loom(TM) manual for help."
+msgstr "Qingchayue Loom(TM) Shouce Huoqu Bangzhu."
+
+#: engines/scumm/dialogs.cpp:660
+msgid "Practice"
+msgstr "Lianxi"
+
+#: engines/scumm/dialogs.cpp:661
+msgid "Expert"
+msgstr "Zhuanjia"
+
+#: engines/scumm/help.cpp:74
+msgid "Common keyboard commands:"
+msgstr "Changyong Jianpan Mingling:"
+
+#: engines/scumm/help.cpp:75
+msgid "Save / Load dialog"
+msgstr "Baocun/Zairu Duihua"
+
+#: engines/scumm/help.cpp:77
+msgid "Skip line of text"
+msgstr "Tiaoguo cihang wenben"
+
+#: engines/scumm/help.cpp:78
+msgid "Esc"
+msgstr "Esc"
+
+#: engines/scumm/help.cpp:78
+msgid "Skip cutscene"
+msgstr "Tiaoguo Guochang"
+
+#: engines/scumm/help.cpp:79
+msgid "Space"
+msgstr "Kongge"
+
+#: engines/scumm/help.cpp:79
+msgid "Pause game"
+msgstr "Zanting Youxi"
+
+#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:85
+#: engines/scumm/help.cpp:96 engines/scumm/help.cpp:97
+#: engines/scumm/help.cpp:98 engines/scumm/help.cpp:99
+#: engines/scumm/help.cpp:100 engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102 engines/scumm/help.cpp:103
+msgid "Ctrl"
+msgstr "Ctrl"
+
+#: engines/scumm/help.cpp:80
+msgid "Load game state 1-10"
+msgstr "Zairu Youxi Cundang 1-10"
+
+#: engines/scumm/help.cpp:81 engines/scumm/help.cpp:85
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:101
+#: engines/scumm/help.cpp:102 engines/scumm/help.cpp:103
+msgid "Alt"
+msgstr "Alt"
+
+#: engines/scumm/help.cpp:81
+msgid "Save game state 1-10"
+msgstr "Baocun Youxi Cundang 1-10"
+
+#: engines/scumm/help.cpp:87 engines/scumm/help.cpp:90
+msgid "Enter"
+msgstr "Huiche"
+
+#: engines/scumm/help.cpp:88
+msgid "Music volume up / down"
+msgstr "Yinyue YInliang Gao/Di"
+
+#: engines/scumm/help.cpp:89
+msgid "Text speed slower / faster"
+msgstr "Wenben Sudu Man/Kuai"
+
+#: engines/scumm/help.cpp:90
+msgid "Simulate left mouse button"
+msgstr "Moni Shubiao Zuojian"
+
+#: engines/scumm/help.cpp:91
+msgid "Tab"
+msgstr "Tab"
+
+#: engines/scumm/help.cpp:91
+msgid "Simulate right mouse button"
+msgstr "Moni Shubiao Youjian"
+
+#: engines/scumm/help.cpp:94
+msgid "Special keyboard commands:"
+msgstr "Jianpan Teshu MIngling:"
+
+#: engines/scumm/help.cpp:95
+msgid "Show / Hide console"
+msgstr "Xianshi/YIncang Kongzhitai"
+
+#: engines/scumm/help.cpp:96
+msgid "Start the debugger"
+msgstr "Yunxing Tiaoshiqi"
+
+#: engines/scumm/help.cpp:97
+msgid "Show memory consumption"
+msgstr "Xianshi Neicun xioahao"
+
+#: engines/scumm/help.cpp:98
+msgid "Run in fast mode (*)"
+msgstr "zai Kuaisu Moshi Zhong YUnxing (*)"
+
+#: engines/scumm/help.cpp:99
+msgid "Run in really fast mode (*)"
+msgstr "Zai Chaokuai Moshi XIa yunxing(*)"
+
+#: engines/scumm/help.cpp:100
+msgid "Toggle mouse capture"
+msgstr "Qiehuan Shubiao buzhuo"
+
+#: engines/scumm/help.cpp:101
+msgid "Switch between graphics filters"
+msgstr "QIehuan Tuxiang Guolvqi"
+
+#: engines/scumm/help.cpp:102
+msgid "Increase / Decrease scale factor"
+msgstr "Zengjia / Jianshao suofang Yinzi"
+
+#: engines/scumm/help.cpp:103
+msgid "Toggle aspect-ratio correction"
+msgstr "Qiehuan bili Jiaozheng"
+
+#: engines/scumm/help.cpp:108
+msgid "* Note that using ctrl-f and"
+msgstr "* Zhuyi Ctrl-f He"
+
+#: engines/scumm/help.cpp:109
+msgid " ctrl-g are not recommended"
+msgstr " Ctrl-g BIngbu zhichi"
+
+#: engines/scumm/help.cpp:110
+msgid " since they may cause crashes"
+msgstr " Yinwei Keneng zaocheng cuowu"
+
+#: engines/scumm/help.cpp:111
+msgid " or incorrect game behavior."
+msgstr " Huo Buzhengque de Youxi xingwei"
+
+#: engines/scumm/help.cpp:115
+msgid "Spinning drafts on the keyboard:"
+msgstr "Jianpanshang xuanzhuan Zaogao:"
+
+#: engines/scumm/help.cpp:117
+msgid "Main game controls:"
+msgstr "Youxi zhuyao Kongzhi:"
+
+#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137
+#: engines/scumm/help.cpp:162
+msgid "Push"
+msgstr "Tui"
+
+#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138
+#: engines/scumm/help.cpp:163
+msgid "Pull"
+msgstr "La"
+
+#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139
+#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:198
+#: engines/scumm/help.cpp:208
+msgid "Give"
+msgstr "gei"
+
+#: engines/scumm/help.cpp:125 engines/scumm/help.cpp:140
+#: engines/scumm/help.cpp:165 engines/scumm/help.cpp:191
+#: engines/scumm/help.cpp:209
+msgid "Open"
+msgstr "Dakai"
+
+#: engines/scumm/help.cpp:127
+msgid "Go to"
+msgstr "Qudao"
+
+#: engines/scumm/help.cpp:128
+msgid "Get"
+msgstr "Dedao"
+
+#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:153
+#: engines/scumm/help.cpp:171 engines/scumm/help.cpp:199
+#: engines/scumm/help.cpp:214 engines/scumm/help.cpp:225
+#: engines/scumm/help.cpp:251
+msgid "Use"
+msgstr "Shiyong"
+
+#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:142
+msgid "Read"
+msgstr "du"
+
+#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:148
+msgid "New kid"
+msgstr "Xin kid"
+
+#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154
+#: engines/scumm/help.cpp:172
+msgid "Turn on"
+msgstr "DaKai"
+
+#: engines/scumm/help.cpp:133 engines/scumm/help.cpp:155
+#: engines/scumm/help.cpp:173
+msgid "Turn off"
+msgstr "Guanbi"
+
+#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168
+#: engines/scumm/help.cpp:195
+msgid "Walk to"
+msgstr "Zouxiang"
+
+#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169
+#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:211
+#: engines/scumm/help.cpp:228
+msgid "Pick up"
+msgstr "Jianqi"
+
+#: engines/scumm/help.cpp:145 engines/scumm/help.cpp:170
+msgid "What is"
+msgstr "Shenme"
+
+#: engines/scumm/help.cpp:147
+msgid "Unlock"
+msgstr "Jiesuo"
+
+#: engines/scumm/help.cpp:150
+msgid "Put on"
+msgstr "Chuanshang"
+
+#: engines/scumm/help.cpp:151
+msgid "Take off"
+msgstr "Tuoxia"
+
+#: engines/scumm/help.cpp:157
+msgid "Fix"
+msgstr "Xiufu"
+
+#: engines/scumm/help.cpp:159
+msgid "Switch"
+msgstr "Qiehuan"
+
+#: engines/scumm/help.cpp:167 engines/scumm/help.cpp:229
+msgid "Look"
+msgstr "Kan"
+
+#: engines/scumm/help.cpp:174 engines/scumm/help.cpp:224
+msgid "Talk"
+msgstr "Shuohua"
+
+#: engines/scumm/help.cpp:175
+msgid "Travel"
+msgstr "LvXing"
+
+#: engines/scumm/help.cpp:176
+msgid "To Henry / To Indy"
+msgstr "Gei Henry/ Gei Indy"
+
+#. I18N: These are different musical notes
+#: engines/scumm/help.cpp:180
+msgid "play C minor on distaff"
+msgstr "Yanzou C Xiaodiao"
+
+#: engines/scumm/help.cpp:181
+msgid "play D on distaff"
+msgstr "Yanzou D"
+
+#: engines/scumm/help.cpp:182
+msgid "play E on distaff"
+msgstr "Yanzou E"
+
+#: engines/scumm/help.cpp:183
+msgid "play F on distaff"
+msgstr "Yanozu F"
+
+#: engines/scumm/help.cpp:184
+msgid "play G on distaff"
+msgstr "Yanzou G"
+
+#: engines/scumm/help.cpp:185
+msgid "play A on distaff"
+msgstr "Yanzou A"
+
+#: engines/scumm/help.cpp:186
+msgid "play B on distaff"
+msgstr "Yanzou B"
+
+#: engines/scumm/help.cpp:187
+msgid "play C major on distaff"
+msgstr "Yanzou C Dadiao"
+
+#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215
+msgid "puSh"
+msgstr "Tui"
+
+#: engines/scumm/help.cpp:194 engines/scumm/help.cpp:216
+msgid "pull (Yank)"
+msgstr "La"
+
+#: engines/scumm/help.cpp:197 engines/scumm/help.cpp:213
+#: engines/scumm/help.cpp:249
+msgid "Talk to"
+msgstr "Shuohua"
+
+#: engines/scumm/help.cpp:200 engines/scumm/help.cpp:212
+msgid "Look at"
+msgstr "Kanxiang"
+
+#: engines/scumm/help.cpp:201
+msgid "turn oN"
+msgstr "Dakai"
+
+#: engines/scumm/help.cpp:202
+msgid "turn oFf"
+msgstr "Guanbi"
+
+#: engines/scumm/help.cpp:218
+msgid "KeyUp"
+msgstr "TaiqiAnjian"
+
+#: engines/scumm/help.cpp:218
+msgid "Highlight prev dialogue"
+msgstr "Gaoliang Zhiqian Duihua"
+
+#: engines/scumm/help.cpp:219
+msgid "KeyDown"
+msgstr "AnxiaAnjian"
+
+#: engines/scumm/help.cpp:219
+msgid "Highlight next dialogue"
+msgstr "Gaoliang Zhihou Duihua"
+
+#: engines/scumm/help.cpp:223
+msgid "Walk"
+msgstr "Zou"
+
+#: engines/scumm/help.cpp:226 engines/scumm/help.cpp:235
+#: engines/scumm/help.cpp:242 engines/scumm/help.cpp:250
+msgid "Inventory"
+msgstr "Wupin"
+
+#: engines/scumm/help.cpp:227
+msgid "Object"
+msgstr "Dongxi"
+
+#: engines/scumm/help.cpp:230
+msgid "Black and White / Color"
+msgstr "Heibai / Caise"
+
+#: engines/scumm/help.cpp:233
+msgid "Eyes"
+msgstr "yanjing"
+
+#: engines/scumm/help.cpp:234
+msgid "Tongue"
+msgstr "Shetou"
+
+#: engines/scumm/help.cpp:236
+msgid "Punch"
+msgstr "Quantou"
+
+#: engines/scumm/help.cpp:237
+msgid "Kick"
+msgstr "Ti"
+
+#: engines/scumm/help.cpp:240 engines/scumm/help.cpp:248
+msgid "Examine"
+msgstr "Jiancha"
+
+#: engines/scumm/help.cpp:241
+msgid "Regular cursor"
+msgstr "Putong Guangbiao"
+
+#. I18N: Comm is a communication device
+#: engines/scumm/help.cpp:244
+msgid "Comm"
+msgstr "Tongxin"
+
+#: engines/scumm/help.cpp:247
+msgid "Save / Load / Options"
+msgstr "Baocun / Zairu / Xuanxiang"
+
+#: engines/scumm/help.cpp:256
+msgid "Other game controls:"
+msgstr "QIta youxi Kongzhi:"
+
+#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:268
+msgid "Inventory:"
+msgstr "Wupin:"
+
+#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275
+msgid "Scroll list up"
+msgstr "LIebiao Shanghua"
+
+#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:276
+msgid "Scroll list down"
+msgstr "LIebiao Xiahua"
+
+#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:269
+msgid "Upper left item"
+msgstr "Zuoshang Wupin"
+
+#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271
+msgid "Lower left item"
+msgstr "Zuoxia Wupin"
+
+#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:272
+msgid "Upper right item"
+msgstr "Youshang Wupin"
+
+#: engines/scumm/help.cpp:264 engines/scumm/help.cpp:274
+msgid "Lower right item"
+msgstr "Youxia Wupin"
+
+#: engines/scumm/help.cpp:270
+msgid "Middle left item"
+msgstr "Zhongzuo Wupin"
+
+#: engines/scumm/help.cpp:273
+msgid "Middle right item"
+msgstr "Zhongyou Wupin"
+
+#: engines/scumm/help.cpp:280 engines/scumm/help.cpp:285
+msgid "Switching characters:"
+msgstr "Qiehuan Juese"
+
+#: engines/scumm/help.cpp:282
+msgid "Second kid"
+msgstr "Dierge Kid"
+
+#: engines/scumm/help.cpp:283
+msgid "Third kid"
+msgstr "Disange Kid"
+
+#: engines/scumm/help.cpp:292
+msgid "Toggle Inventory/IQ Points display"
+msgstr "Qiehuan Wupin/IQ Dian Xianshi"
+
+#: engines/scumm/help.cpp:293
+msgid "Toggle Keyboard/Mouse Fighting (*)"
+msgstr "Qiehuan JInapan/Shubiao Zhandou (*)"
+
+#: engines/scumm/help.cpp:295
+msgid "* Keyboard Fighting is always on,"
+msgstr "* Jianpan Zhandou zongshi Kaiqi,"
+
+#: engines/scumm/help.cpp:296
+msgid " so despite the in-game message this"
+msgstr " Suoyi Hulue youxi nei xinxi"
+
+#: engines/scumm/help.cpp:297
+msgid " actually toggles Mouse Fighting Off/On"
+msgstr " Zhe shiji shang shi Zai qiehuan Shubiao Zhandou de Kaiguan"
+
+#: engines/scumm/help.cpp:304
+msgid "Fighting controls (numpad):"
+msgstr "Zhandou Kongzhi (zhuzijianpan):"
+
+#: engines/scumm/help.cpp:305 engines/scumm/help.cpp:306
+#: engines/scumm/help.cpp:307
+msgid "Step back"
+msgstr "Shangyibu"
+
+#: engines/scumm/help.cpp:308
+msgid "Block high"
+msgstr "Zudang Gaochu"
+
+#: engines/scumm/help.cpp:309
+msgid "Block middle"
+msgstr "Zudang Zhongjian"
+
+#: engines/scumm/help.cpp:310
+msgid "Block low"
+msgstr "Zudang Dichu"
+
+#: engines/scumm/help.cpp:311
+msgid "Punch high"
+msgstr "Quanda Gaochu"
+
+#: engines/scumm/help.cpp:312
+msgid "Punch middle"
+msgstr "Quanda Zhongjian"
+
+#: engines/scumm/help.cpp:313
+msgid "Punch low"
+msgstr "Quanda Dichu"
+
+#: engines/scumm/help.cpp:315
+msgid "Sucker punch"
+msgstr "Sucker Punch"
+
+#: engines/scumm/help.cpp:318
+msgid "These are for Indy on left."
+msgstr "Weile zai Zuobian de Indy"
+
+#: engines/scumm/help.cpp:319
+msgid "When Indy is on the right,"
+msgstr "Dnag Indy Zai Youbian Shi,"
+
+#: engines/scumm/help.cpp:320
+msgid "7, 4, and 1 are switched with"
+msgstr "7, 4 He 1 Fenbie keyi Yong"
+
+#: engines/scumm/help.cpp:321
+msgid "9, 6, and 3, respectively."
+msgstr "9, 6, 3 Laiqiehuan."
+
+#: engines/scumm/help.cpp:328
+msgid "Biplane controls (numpad):"
+msgstr "Shuangmian Kongzhi (shuzijianpan):"
+
+#: engines/scumm/help.cpp:329
+msgid "Fly to upper left"
+msgstr "Feiwang Zuoshang"
+
+#: engines/scumm/help.cpp:330
+msgid "Fly to left"
+msgstr "Feiwang Zuobian"
+
+#: engines/scumm/help.cpp:331
+msgid "Fly to lower left"
+msgstr "Feiwang Zuoxia"
+
+#: engines/scumm/help.cpp:332
+msgid "Fly upwards"
+msgstr "Xinagshang Fei"
+
+#: engines/scumm/help.cpp:333
+msgid "Fly straight"
+msgstr "Zhifei"
+
+#: engines/scumm/help.cpp:334
+msgid "Fly down"
+msgstr "Xiangxia Fei"
+
+#: engines/scumm/help.cpp:335
+msgid "Fly to upper right"
+msgstr "Feiwang YouShang"
+
+#: engines/scumm/help.cpp:336
+msgid "Fly to right"
+msgstr "Feiwang Youbian"
+
+#: engines/scumm/help.cpp:337
+msgid "Fly to lower right"
+msgstr "Feiwang Youxia"
+
+#: engines/scumm/input.cpp:578
+msgid "Snap scroll on"
+msgstr "Snap hundong kai"
+
+#: engines/scumm/input.cpp:580
+msgid "Snap scroll off"
+msgstr "Snap Gundong Guan"
+
+#: engines/scumm/input.cpp:593
+msgid "Music volume: "
+msgstr "Yinyue Yinliang:"
+
+#: engines/scumm/input.cpp:610
+msgid "Subtitle speed: "
+msgstr "Zimu Sudu:"
+
+#: engines/scumm/scumm.cpp:1850
+#, c-format
+msgid ""
+"Native MIDI support requires the Roland Upgrade from LucasArts,\n"
+"but %s is missing. Using AdLib instead."
+msgstr ""
+"Bendi MIDI Zhichi Xuyao Cong LucasArts Shengji Zhi Roland,\n"
+"Dnahsi %s meiyou zhaodao. Shiyong AdLib."
+
+#: engines/scumm/scumm.cpp:2666
+msgid ""
+"Usually, Maniac Mansion would start now. But for that to work, the game "
+"files for Maniac Mansion have to be in the 'Maniac' directory inside the "
+"Tentacle game directory, and the game has to be added to ScummVM."
+msgstr ""
+"Tongchang, Maniac mansion Huizai XIanzai kaishi. Raner, Manian mansion De "
+"youxi Wenjian Xuyao zai 'maniac'Mulu Nei , weiyu Tentacle Youxi Mulu, Ci "
+"Youxi Xuyao Bei tianjia dao ScummVM Zhong."
+
+#: engines/scumm/players/player_v3m.cpp:129
+msgid ""
+"Could not find the 'Loom' Macintosh executable to read the\n"
+"instruments from. Music will be disabled."
+msgstr ""
+"Wufa Zhaodao 'Loom' Macintosh Chengxu lai\n"
+" Duru Yinyue. Yinyue Huibei Jinyong."
+
+#: engines/scumm/players/player_v5m.cpp:107
+msgid ""
+"Could not find the 'Monkey Island' Macintosh executable to read the\n"
+"instruments from. Music will be disabled."
+msgstr ""
+"Wufa Zhaodao 'monkey Island' Macintosh Chengxu lai Duru YInyue. yinyue "
+"Huibei Jinyong."
+
+#: engines/sherlock/detection.cpp:71
+msgid "Use original savegame dialog"
+msgstr "Shiyong Yuanshi Youxi baocun Duihuakuang"
+
+#: engines/sherlock/detection.cpp:72
+msgid ""
+"Files button in-game shows original savegame dialog rather than the ScummVM "
+"menu"
+msgstr ""
+"YouxiNei wenjian Anniu shiyong Yuanshi Youxi Duihuakuang Erfei ScummVM Caidan"
+
+#: engines/sherlock/detection.cpp:81
+msgid "Pixellated scene transitions"
+msgstr "Xiangsuhua Changjing Qiehuan"
+
+#: engines/sherlock/detection.cpp:82
+msgid "When changing scenes, a randomized pixel transition is done"
+msgstr "Dang Qiehuan Changjingshi, Shiyong Suiji Xiangsu zhuanhuan"
+
+#: engines/sherlock/detection.cpp:91
+msgid "Don't show hotspots when moving mouse"
+msgstr "Dnag Yidong shubiao Shi Buyao Xianshi Redian"
+
+#: engines/sherlock/detection.cpp:92
+msgid ""
+"Only show hotspot names after you actually click on a hotspot or action "
+"button"
+msgstr "JInzai Dianji Redian Huo Dongzuo Anjianhou Xianshi Redianming"
+
+#: engines/sherlock/detection.cpp:101
+msgid "Show character portraits"
+msgstr "Xianshi Juese Huaxiang"
+
+#: engines/sherlock/detection.cpp:102
+msgid "Show portraits for the characters when conversing"
+msgstr "Jiaotan Shi Xianshi Juese Huaxiang"
+
+#: engines/sherlock/detection.cpp:111
+msgid "Slide dialogs into view"
+msgstr "Huadon Duigua dao SHituzhong"
+
+#: engines/sherlock/detection.cpp:112
+msgid "Slide UI dialogs into view, rather than simply showing them immediately"
+msgstr "Jiang UI Duihuakuang Huaru Shitu, Erfei Turan Chuxian"
+
+#: engines/sherlock/detection.cpp:121
+msgid "Transparent windows"
+msgstr "Touming Chuangkou"
+
+#: engines/sherlock/detection.cpp:122
+msgid "Show windows with a partially transparent background"
+msgstr "Xianshi Diayou Bantouming Beijing de Chuangkou"
+
+#: engines/sky/compact.cpp:130
+msgid ""
+"Unable to find \"sky.cpt\" file!\n"
+"Please download it from www.scummvm.org"
+msgstr ""
+"Wufa Zhaodao \"sky.cpt\" Wenjian\n"
+"Qing Cong www.cummvm.org Xiazai"
+
+#: engines/sky/compact.cpp:141
+msgid ""
+"The \"sky.cpt\" file has an incorrect size.\n"
+"Please (re)download it from www.scummvm.org"
+msgstr ""
+"Wenjian \"sky.cpt\" Chicun Cuowu.\n"
+"Qing Cong www.scummvm.org Chongxin Xiazai"
+
+#: engines/sky/detection.cpp:44
+msgid "Floppy intro"
+msgstr "Ruanpan Jieshao"
+
+#: engines/sky/detection.cpp:45
+msgid "Use the floppy version's intro (CD version only)"
+msgstr "Shiyong Ruanpan Banben JIeshao (jin CD banben)"
+
+#: engines/sword1/animation.cpp:524
+#, c-format
+msgid "PSX stream cutscene '%s' cannot be played in paletted mode"
+msgstr "PSX liu Changjing '%s' Wufa zai Tiaosiban Moshi xia Bofang"
+
+#: engines/sword1/animation.cpp:545 engines/sword2/animation.cpp:445
+msgid "DXA cutscenes found but ScummVM has been built without zlib"
+msgstr "Zhaodao DXA Guochang Danshi ScummVM Meiyou yu Zlib bianyi"
+
+#: engines/sword1/animation.cpp:561 engines/sword2/animation.cpp:461
+msgid ""
+"MPEG-2 cutscenes found but ScummVM has been built without MPEG-2 support"
+msgstr "MPEG-2 Guocheng Zhaodao Dnashi ScummVM Meiyou He MPEG-2 Zhichi Bianyi"
+
+#: engines/sword1/animation.cpp:568 engines/sword2/animation.cpp:470
+#, c-format
+msgid "Cutscene '%s' not found"
+msgstr "Guochang '%s' Weizhaodao"
+
+#: engines/sword1/control.cpp:863
+msgid ""
+"ScummVM found that you have old savefiles for Broken Sword 1 that should be "
+"converted.\n"
+"The old save game format is no longer supported, so you will not be able to "
+"load your games if you don't convert them.\n"
+"\n"
+"Press OK to convert them now, otherwise you will be asked again the next "
+"time you start the game.\n"
+msgstr ""
+"ScummVM Zhaodaole Zhiqian De Broken Sword 1 Cundang, qie YInggai Bei "
+"zhuanhuan.\n"
+"Zhiqian de cundang Geshi BUzai Zhichi, Nin Bixu Xianzhuanhuan Caineng Duqu "
+"Cundang\n"
+"Dianji Queding Lia zhuanhuancundang, Fouze NIn Huizai Xiaci Kaishi Youxi Shi "
+"bei Zaici Tishi\n"
+
+#: engines/sword1/control.cpp:1232
+#, c-format
+msgid ""
+"Target new save game already exists!\n"
+"Would you like to keep the old save game (%s) or the new one (%s)?\n"
+msgstr ""
+"Mubiao Xin Cundang Yijing Cunzai!\n"
+"Niyao Baocun jiude Cundang (%s) Haishi Xinde(%s)?\n"
+
+#: engines/sword1/control.cpp:1235
+msgid "Keep the old one"
+msgstr "Baoliu Jiude"
+
+#: engines/sword1/control.cpp:1235
+msgid "Keep the new one"
+msgstr "Baoliu Xinde"
+
+#: engines/sword1/logic.cpp:1633
+msgid "This is the end of the Broken Sword 1 Demo"
+msgstr "Zheshi Broken Sword 1 Demo de Jiewei"
+
+#: engines/sword2/animation.cpp:425
+msgid ""
+"PSX cutscenes found but ScummVM has been built without RGB color support"
+msgstr "PSX Guochang zhaodao Danshi ScmummVM Meiyou Zhichi RGB Secai Bianyi"
+
+#: engines/sword2/sword2.cpp:79
+msgid "Show object labels"
+msgstr "Xianshi Wuti Biaoqian"
+
+#: engines/sword2/sword2.cpp:80
+msgid "Show labels for objects on mouse hover"
+msgstr "Dang Shubiao Yishang Shi Xianshi Wuti Biaoqian"
+
+#: engines/sword25/detection.cpp:46
+msgid "Use English speech"
+msgstr ""
+
+#: engines/sword25/detection.cpp:47
+msgid ""
+"Use English speech instead of German for every language other than German"
+msgstr ""
+
+#: engines/teenagent/resources.cpp:96
+msgid ""
+"You're missing the 'teenagent.dat' file. Get it from the ScummVM website"
+msgstr ""
+"Zhaobudao 'teenagent.dat' Wenjian. Cong ScummVM wangzhan Shangmian Dedao"
+
+#: engines/teenagent/resources.cpp:117
+msgid ""
+"The teenagent.dat file is compressed and zlib hasn't been included in this "
+"executable. Please decompress it"
+msgstr ""
+"teenagent.dat Wenjian Yibeiyasuo Bingqie zlib Bingmeiyou Zai chengxu Zhong. "
+"Qing jieya."
+
+#: engines/wintermute/detection.cpp:58
+msgid "Show FPS-counter"
+msgstr "Xianshi FPS Jishuqi"
+
+#: engines/wintermute/detection.cpp:59
+msgid "Show the current number of frames per second in the upper left corner"
+msgstr "Zai Zuoshangjiao Xianshi Xianzai Meimiaozhong Zhenshu"
+
+#: engines/zvision/detection_tables.h:52
+msgid "Use the original save/load screens instead of the ScummVM interface"
+msgstr "Shiyong Yuanshi baocun/zairu Pingmu Erfei ScummVM jiemian"
+
+#: engines/zvision/detection_tables.h:61
+msgid "Double FPS"
+msgstr "Shuangbei FPS"
+
+#: engines/zvision/detection_tables.h:62
+msgid "Increase framerate from 30 to 60 FPS"
+msgstr "Zengjia zhenlv cong 30 dao 60 FPS"
+
+#: engines/zvision/detection_tables.h:71
+msgid "Enable Venus"
+msgstr "Qiyong Venus"
+
+#: engines/zvision/detection_tables.h:72
+msgid "Enable the Venus help system"
+msgstr "Qiyong Venus Bangzhu Xitong"
+
+#: engines/zvision/detection_tables.h:81
+msgid "Disable animation while turning"
+msgstr "zhuanxinag shi Jinyong Donghua"
+
+#: engines/zvision/detection_tables.h:82
+msgid "Disable animation while turning in panorama mode"
+msgstr "Quanjing Moshi xia Zhuanxiang shi Jinyong Donghua"
+
+#: engines/zvision/detection_tables.h:91
+msgid "Use high resolution MPEG video"
+msgstr "Shiyong Gaofenbianlv MPEG shipin"
+
+#: engines/zvision/detection_tables.h:92
+msgid "Use MPEG video from the DVD version, instead of lower resolution AVI"
+msgstr "Cong DVD Banben Zhong shiyong MPEG shipin, erfei Difenbianlv AVI"
diff --git a/ports.mk b/ports.mk
index fa380846e1..dce5a5d153 100644
--- a/ports.mk
+++ b/ports.mk
@@ -53,8 +53,43 @@ ifdef DYNAMIC_MODULES
endif
# Special target to create a application wrapper for Mac OS X
+
+ifdef USE_DOCKTILEPLUGIN
+
+# The NsDockTilePlugIn needs to be compiled in both 32 and 64 bits irrespective of how ScummVM itself is compiled.
+# Therefore do not use $(CXXFLAGS) and $(LDFLAGS).
+
+ScummVMDockTilePlugin32.o:
+ $(CXX) -mmacosx-version-min=10.6 -arch i386 -O2 -c $(srcdir)/backends/taskbar/macosx/dockplugin/dockplugin.m -o ScummVMDockTilePlugin32.o
+
+ScummVMDockTilePlugin32: ScummVMDockTilePlugin32.o
+ $(CXX) -mmacosx-version-min=10.6 -arch i386 -bundle -framework Foundation -framework AppKit -fobjc-link-runtime ScummVMDockTilePlugin32.o -o ScummVMDockTilePlugin32
+
+ScummVMDockTilePlugin64.o:
+ $(CXX) -mmacosx-version-min=10.6 -arch x86_64 -O2 -c $(srcdir)/backends/taskbar/macosx/dockplugin/dockplugin.m -o ScummVMDockTilePlugin64.o
+
+ScummVMDockTilePlugin64: ScummVMDockTilePlugin64.o
+ $(CXX) -mmacosx-version-min=10.6 -arch x86_64 -bundle -framework Foundation -framework AppKit -fobjc-link-runtime ScummVMDockTilePlugin64.o -o ScummVMDockTilePlugin64
+
+ScummVMDockTilePlugin: ScummVMDockTilePlugin32 ScummVMDockTilePlugin64
+ lipo -create ScummVMDockTilePlugin32 ScummVMDockTilePlugin64 -output ScummVMDockTilePlugin
+
+scummvm.docktileplugin: ScummVMDockTilePlugin
+ mkdir -p scummvm.docktileplugin/Contents
+ cp $(srcdir)/dists/macosx/dockplugin/Info.plist scummvm.docktileplugin/Contents
+ mkdir -p scummvm.docktileplugin/Contents/MacOS
+ cp ScummVMDockTilePlugIn scummvm.docktileplugin/Contents/MacOS/
+ chmod 644 scummvm.docktileplugin/Contents/MacOS/ScummVMDockTilePlugIn
+
+endif
+
bundle_name = ScummVM.app
+
+ifdef USE_DOCKTILEPLUGIN
+bundle: scummvm-static scummvm.docktileplugin
+else
bundle: scummvm-static
+endif
mkdir -p $(bundle_name)/Contents/MacOS
mkdir -p $(bundle_name)/Contents/Resources
echo "APPL????" > $(bundle_name)/Contents/PkgInfo
@@ -62,7 +97,8 @@ bundle: scummvm-static
ifdef USE_SPARKLE
mkdir -p $(bundle_name)/Contents/Frameworks
cp $(srcdir)/dists/macosx/dsa_pub.pem $(bundle_name)/Contents/Resources/
- cp -R $(STATICLIBPATH)/Sparkle.framework $(bundle_name)/Contents/Frameworks/
+ rm -rf $(bundle_name)/Contents/Frameworks/Sparkle.framework
+ cp -R $(SPARKLEPATH)/Sparkle.framework $(bundle_name)/Contents/Frameworks/
endif
cp $(srcdir)/icons/scummvm.icns $(bundle_name)/Contents/Resources/
cp $(DIST_FILES_DOCS) $(bundle_name)/
@@ -75,6 +111,10 @@ endif
cp scummvm-static $(bundle_name)/Contents/MacOS/scummvm
chmod 755 $(bundle_name)/Contents/MacOS/scummvm
$(STRIP) $(bundle_name)/Contents/MacOS/scummvm
+ifdef USE_DOCKTILEPLUGIN
+ mkdir -p $(bundle_name)/Contents/PlugIns
+ cp -r scummvm.docktileplugin $(bundle_name)/Contents/PlugIns/
+endif
iphonebundle: iphone
mkdir -p $(bundle_name)
@@ -223,6 +263,8 @@ ifneq ($(BACKEND), iphone)
ifneq ($(BACKEND), ios7)
# Static libaries, used for the scummvm-static and iphone targets
OSX_STATIC_LIBS := `$(SDLCONFIG) --static-libs`
+# With sdl2-config we don't always get the OpenGL framework
+OSX_STATIC_LIBS += -framework OpenGL
endif
endif
@@ -288,7 +330,10 @@ OSX_ZLIB ?= $(STATICLIBPATH)/lib/libz.a
endif
ifdef USE_SPARKLE
-OSX_STATIC_LIBS += -framework Sparkle -F$(STATICLIBPATH)
+ifneq ($(SPARKLEPATH),)
+OSX_STATIC_LIBS += -F$(SPARKLEPATH)
+endif
+OSX_STATIC_LIBS += -framework Sparkle -Wl,-rpath,@loader_path/../Frameworks
endif
# Special target to create a static linked binary for Mac OS X.
@@ -341,7 +386,7 @@ osxsnap: bundle
mkdir ScummVM-snapshot/doc/se
cp $(srcdir)/doc/se/LasMig ./ScummVM-snapshot/doc/se/LasMig
cp $(srcdir)/doc/se/Snabbstart ./ScummVM-snapshot/doc/se/Snabbstart
- /Developer/Tools/SetFile -t ttro -c ttxt ./ScummVM-snapshot/*
+ $(XCODETOOLSPATH)/SetFile -t ttro -c ttxt ./ScummVM-snapshot/*
xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/cz/*
xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/da/*
xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/de/*
@@ -350,17 +395,20 @@ osxsnap: bundle
xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/it/*
xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/no-nb/*
xattr -w "com.apple.TextEncoding" "utf-8;134217984" ./ScummVM-snapshot/doc/se/*
- /Developer/Tools/CpMac -r $(bundle_name) ./ScummVM-snapshot/
+ $(XCODETOOLSPATH)/CpMac -r $(bundle_name) ./ScummVM-snapshot/
cp $(srcdir)/dists/macosx/DS_Store ./ScummVM-snapshot/.DS_Store
cp $(srcdir)/dists/macosx/background.jpg ./ScummVM-snapshot/background.jpg
- /Developer/Tools/SetFile -a V ./ScummVM-snapshot/.DS_Store
- /Developer/Tools/SetFile -a V ./ScummVM-snapshot/background.jpg
+ $(XCODETOOLSPATH)/SetFile -a V ./ScummVM-snapshot/.DS_Store
+ $(XCODETOOLSPATH)/SetFile -a V ./ScummVM-snapshot/background.jpg
hdiutil create -ov -format UDZO -imagekey zlib-level=9 -fs HFS+ \
-srcfolder ScummVM-snapshot \
-volname "ScummVM" \
ScummVM-snapshot.dmg
rm -rf ScummVM-snapshot
+publish-appcast:
+ scp dists/macosx/scummvm_appcast.xml www.scummvm.org:/var/www/html/appcasts/macosx/release.xml
+
#
# Windows specific
#
@@ -439,12 +487,12 @@ CUR_BRANCH := $(shell cd $(srcdir); git describe --all |cut -d '-' -f 4-)
ideprojects: devtools/create_project
ifeq ($(VER_DIRTY), -dirty)
- $(error You have uncommitted changes)
-endif
+ $(error You have uncommitted changes)
+endif
ifeq "$(CUR_BRANCH)" "heads/master"
- $(error You cannot do it on master)
+ $(error You cannot do it on master)
else ifeq "$(CUR_BRANCH)" ""
- $(error You must be on a release branch)
+ $(error You must be on a release branch)
endif
@echo Creating Code::Blocks project files...
@cd $(srcdir)/dists/codeblocks && ../../devtools/create_project/create_project ../.. --codeblocks >/dev/null && git add -f engines/plugins_table.h *.workspace *.cbp
diff --git a/test/common/algorithm.h b/test/common/algorithm.h
index ccf6469f67..eeed59d821 100644
--- a/test/common/algorithm.h
+++ b/test/common/algorithm.h
@@ -25,6 +25,34 @@ class AlgorithmTestSuite : public CxxTest::TestSuite {
return true;
}
+ /**
+ * Auxiliary function to check the equality of two generic collections (A and B), from one_first to one_last.
+ *
+ * @note: It assumes that other has at least (one_last - one-first) lenght, starting from other_first.
+ *
+ * @param one_first: The first element of the first collection to be compared.
+ * @param one_last: The last element of the first collection to be compared.
+ * @param other_first: The first element of the collection to be compared.
+ * @return true if, for each index i in [one_first, one_last), A[i] == B[i], false otherwise.
+ */
+ template<typename It>
+ bool checkEqual(It one_first, It one_last, It other_first) {
+ if (one_first == one_last)
+ return true;
+
+ // Check whether two containers have the same items in the same order,
+ // starting from some iterators one_first and other_first
+ //
+ // It iterates through the containers, comparing the elements one by one.
+ // If it finds a discrepancy, it returns false. Otherwise, it returns true.
+
+ for (; one_first != one_last; ++one_first, ++other_first)
+ if (*one_first != *other_first)
+ return false;
+
+ return true;
+ }
+
struct Item {
int value;
Item(int v) : value(v) {}
@@ -97,4 +125,32 @@ public:
Common::sort(list.begin(), list.end());
TS_ASSERT_EQUALS(checkSort(list.begin(), list.end(), Common::Less<Item>()), true);
}
+
+ void test_string_replace() {
+
+ Common::String original = "Hello World";
+ Common::String expected = "Hells Wsrld";
+
+ Common::replace(original.begin(), original.end(), 'o', 's');
+
+ TS_ASSERT_EQUALS(original, expected);
+ }
+
+ void test_container_replace() {
+
+ Common::List<int> original;
+ Common::List<int> expected;
+ for (int i = 0; i < 6; ++i) {
+ original.push_back(i);
+ if (i == 3) {
+ expected.push_back(5);
+ } else {
+ expected.push_back(i);
+ }
+ }
+
+ Common::replace(original.begin(), original.end(), 3, 5);
+
+ TS_ASSERT_EQUALS(checkEqual(original.begin(), original.end(), expected.begin()), true);
+ }
};
diff --git a/test/common/array.h b/test/common/array.h
index 64354abc00..2dc67837db 100644
--- a/test/common/array.h
+++ b/test/common/array.h
@@ -354,3 +354,43 @@ class ArrayTestSuite : public CxxTest::TestSuite
}
};
+
+struct ListElement {
+ int value;
+
+ ListElement(int v) : value(v) {}
+};
+
+static int compareInts(const void *a, const void *b) {
+ return ((ListElement *)a)->value - ((ListElement *)b)->value;
+}
+
+class SortedArrayTestSuite : public CxxTest::TestSuite {
+public:
+ void test_insert() {
+ Common::SortedArray<ListElement *> container(compareInts);
+ Common::SortedArray<ListElement *>::iterator iter;
+
+ // Fill the container with some random data
+ container.insert(new ListElement(1));
+ container.insert(new ListElement(7));
+ container.insert(new ListElement(8));
+ container.insert(new ListElement(3));
+ container.insert(new ListElement(5));
+ container.insert(new ListElement(4));
+ container.insert(new ListElement(9));
+ container.insert(new ListElement(2));
+ container.insert(new ListElement(6));
+
+ // Verify contents are correct
+ iter = container.begin();
+
+ for (int i = 1; i < 10; i++) {
+ TS_ASSERT_EQUALS((*iter)->value, i);
+ ++iter;
+ }
+
+ TS_ASSERT_EQUALS(iter, container.end());
+ }
+
+};
diff --git a/test/common/str.h b/test/common/str.h
index 3ab5d828c1..461b26088a 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -419,4 +419,78 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(scumm_strnicmp("abCd", "ABCde", 4), 0);
TS_ASSERT_LESS_THAN(scumm_strnicmp("abCd", "ABCde", 5), 0);
}
+
+ void test_replace() {
+ // Tests created with the results of the STL std::string class
+
+ // --------------------------
+ // Tests without displacement
+ // --------------------------
+ Common::String testString = Common::String("This is the original string.");
+
+ // Positions and sizes as parameters, string as replacement
+ testString.replace(12, 8, Common::String("newnewne"));
+ TS_ASSERT_EQUALS(testString, Common::String("This is the newnewne string."));
+
+ // The same but with char*
+ testString.replace(0, 4, "That");
+ TS_ASSERT_EQUALS(testString, Common::String("That is the newnewne string."));
+
+ // Using iterators (also a terribly useless program as a test).
+ testString.replace(testString.begin(), testString.end(), "That is the supernew string.");
+ TS_ASSERT_EQUALS(testString, Common::String("That is the supernew string."));
+
+ // With sub strings of character arrays.
+ testString.replace(21, 6, "That phrase is new.", 5, 6);
+ TS_ASSERT_EQUALS(testString, Common::String("That is the supernew phrase."));
+
+ // Now with substrings.
+ testString.replace(12, 2, Common::String("That hy is new."), 5, 2);
+ TS_ASSERT_EQUALS(testString, Common::String("That is the hypernew phrase."));
+
+ // --------------------------
+ // Tests with displacement
+ // --------------------------
+ testString = Common::String("Hello World");
+
+ // Positions and sizes as parameters, string as replacement
+ testString.replace(6, 5, Common::String("friends"));
+ TS_ASSERT_EQUALS(testString, Common::String("Hello friends"));
+
+ // The same but with char*
+ testString.replace(0, 5, "Good");
+ TS_ASSERT_EQUALS(testString, Common::String("Good friends"));
+
+ // Using iterators (also a terribly useless program as a test)
+ testString.replace(testString.begin() + 4, testString.begin() + 5, " coffee ");
+ TS_ASSERT_EQUALS(testString, Common::String("Good coffee friends"));
+
+ // With sub strings of character arrays
+ testString.replace(4, 0, "Lorem ipsum expresso dolor sit amet", 11, 9);
+ TS_ASSERT_EQUALS(testString, Common::String("Good expresso coffee friends"));
+
+ // Now with substrings
+ testString.replace(5, 9, Common::String("Displaced ristretto string"), 10, 10);
+ TS_ASSERT_EQUALS(testString, Common::String("Good ristretto coffee friends"));
+
+ // -----------------------
+ // Deep copy compliance
+ // -----------------------
+
+ // Makes a deep copy without changing the length of the original
+ Common::String s1 = "TestTestTestTestTestTestTestTestTestTestTest";
+ Common::String s2(s1);
+ TS_ASSERT_EQUALS(s1, "TestTestTestTestTestTestTestTestTestTestTest");
+ TS_ASSERT_EQUALS(s2, "TestTestTestTestTestTestTestTestTestTestTest");
+ s1.replace(0, 4, "TEST");
+ TS_ASSERT_EQUALS(s1, "TESTTestTestTestTestTestTestTestTestTestTest");
+ TS_ASSERT_EQUALS(s2, "TestTestTestTestTestTestTestTestTestTestTest");
+
+ // Makes a deep copy when we shorten the string
+ Common::String s3 = "TestTestTestTestTestTestTestTestTestTestTest";
+ Common::String s4(s3);
+ s3.replace(0, 32, "");
+ TS_ASSERT_EQUALS(s3, "TestTestTest");
+ TS_ASSERT_EQUALS(s4, "TestTestTestTestTestTestTestTestTestTestTest");
+ }
};
diff --git a/test/module.mk b/test/module.mk
index 11ee6bd200..e591854ace 100644
--- a/test/module.mk
+++ b/test/module.mk
@@ -26,6 +26,7 @@ endif
#TEST_LDFLAGS += -L/usr/X11R6/lib -lX11
+test: CXXFLAGS += -DCOMPILING_TESTS=1
test: test/runner
./test/runner
test/runner: test/runner.cpp $(TEST_LIBS)
diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp
index 21dda15cd0..278dc2d1fc 100644
--- a/video/coktel_decoder.cpp
+++ b/video/coktel_decoder.cpp
@@ -2810,6 +2810,10 @@ void AdvancedVMDDecoder::close() {
_decoder->close();
}
+void AdvancedVMDDecoder::setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp) {
+ _decoder->setSurfaceMemory(mem, width, height, bpp);
+}
+
AdvancedVMDDecoder::VMDVideoTrack::VMDVideoTrack(VMDDecoder *decoder) : _decoder(decoder) {
}
diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h
index a72f76eb9d..44de1c7d68 100644
--- a/video/coktel_decoder.h
+++ b/video/coktel_decoder.h
@@ -568,6 +568,8 @@ public:
bool loadStream(Common::SeekableReadStream *stream);
void close();
+ void setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp);
+
private:
class VMDVideoTrack : public FixedRateVideoTrack {
public:
diff --git a/video/mpegps_decoder.cpp b/video/mpegps_decoder.cpp
index 6942efbe87..d2e9554c8f 100644
--- a/video/mpegps_decoder.cpp
+++ b/video/mpegps_decoder.cpp
@@ -21,7 +21,6 @@
*/
#include "audio/audiostream.h"
-#include "audio/decoders/raw.h"
#include "audio/decoders/mp3.h"
#include "common/debug.h"
#include "common/endian.h"
diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp
index 91f8e1dafc..4f14e2ea4f 100644
--- a/video/psx_decoder.cpp
+++ b/video/psx_decoder.cpp
@@ -24,7 +24,6 @@
// MDEC video emulation based on http://kenai.com/downloads/jpsxdec/Old/PlayStation1_STR_format1-00.txt
#include "audio/audiostream.h"
-#include "audio/mixer.h"
#include "audio/decoders/raw.h"
#include "common/bitstream.h"
#include "common/huffman.h"